import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
import { ArrowLeft, Save, MousePointer2, Circle, Minus, Trash2, X, Sparkles, GitCommit, Plus, Edit2, GripVertical, Move, Check, Copy, Milestone, Hash, Code, Settings } from 'lucide-react';
import { modelAPI, chapterAPI } from '../api/api';
import stateAPI from '../api/stateApi';
import settingsAPI from '../api/settingsApi';
import { useToast } from '../hooks/useToast';
import { useConfirm } from '../hooks/useConfirm';
import { useDialog } from '../hooks/useDialog';
import { useSelect } from '../hooks/useSelect';
import { ToastContainer } from '../components/Toast';
import { Confirm } from '../components/Confirm';
import { Dialog } from '../components/Dialog';
import { Select } from '../components/Select';
import { drawPoint, drawLine, drawLineById, drawLabel, drawPerpendicularById, drawRayById, calculatePerpendicularFoot, DRAWING_STYLES } from '../utils/drawingUtils';
import {
  calculateConstantValue,
  SCALE,
  getDistance,
  updateIntersectionPoints,
  findClickedPoint,
  findClickedLine,
  findClickedPerpendicular,
  findClickedRay,
  convertToMathSymbols
} from '../utils/canvasUtils';
import {
  getConstantValueByName,
  getCanvasCoordinates,
  projectPointOnLine,
  updateSlidingPoints,
  updatePerpendicularFootPoints,
  updateFixedPoints,
  applyDragConstraints,
  applySlidingConstraints,
  validateExpression,
  calculateExpressionValue,
  parseExpressionForRender,
  groupAndAverageValues,
  getAdjustedDisplayValue
} from '../utils/expressionUtils';
import { getAvailableTemplates } from '../templates';
import './GeometryWorkspace.css';

function GeometryWorkspace() {
  const { id } = useParams();
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const chapterIdFromQuery = searchParams.get('chapter_id');
  const modelType = searchParams.get('type'); // 'normal' | 'special'
  const isSpecialMode = modelType === 'special' && !id;

  const canvasRef = useRef(null);

  // Toast、Confirm、Dialog 和 Select hooks
  const toast = useToast();
  const { confirmState, showConfirm } = useConfirm();
  const { dialogState, showDialog } = useDialog();
  const { selectState, showSelect } = useSelect();

  const [chapters, setChapters] = useState([]);
  const [formData, setFormData] = useState({
    chapter_id: chapterIdFromQuery || '',
    title: '',
    order_num: 1,
    is_special: isSpecialMode,
    template_path: ''
  });

  // 工具状态
  const [currentTool, setCurrentTool] = useState('select'); // select, point, line, constant, pointOnLine, perpendicular, ray
  const [selectedItem, setSelectedItem] = useState(null);
  const [dragging, setDragging] = useState(null);
  const [pointOnLineMode, setPointOnLineMode] = useState(null); // { type: 'slide' | 'fixed' | 'divide', lineId: null }
  const [perpendicularMode, setPerpendicularMode] = useState(null); // { fromPoint: null, toLine: null }
  const [parallelMode, setParallelMode] = useState(null); // { fromPoint: null, toLine: null }

  // 常量管理状态
  const [constantMode, setConstantMode] = useState(null); // null | { type: 'angle'|'length'|'area', name: '', editing: boolean, areaMode: 'points'|'compose' }
  const [selectedPointsForConstant, setSelectedPointsForConstant] = useState([]); // 在画布上选中的点
  const [selectedAreasForConstant, setSelectedAreasForConstant] = useState([]); // 选中的面积常量ID（用于组合）

  // 表达式管理状态
  const [expressionMode, setExpressionMode] = useState(null); // null | { parts: [], editing: true }
  const [editingExpressionId, setEditingExpressionId] = useState(null); // 编辑中的表达式ID

  // 约束添加模式
  const [addingConstraintMode, setAddingConstraintMode] = useState(null); // null | 'drag' | 'sliding'

  // 几何数据
  const [geometryData, setGeometryData] = useState({
    points: [], // { id, x, y, label, color, draggable, isIntersection?: boolean, intersectionLines?: [lineId1, lineId2] }
    lines: [],  // { id, startPointId, endPointId, style, color }
    labels: [], // { id, x, y, text, fontSize, color }
    perpendiculars: [], // { id, fromPointId, toLineStartId, toLineEndId }
    parallels: [], // { id, fromPointId, toLineStartId, toLineEndId } - 从fromPoint出发平行于toLine的线
    rays: [], // { id, startPointId, throughPointId, style, color, width } - 从startPoint经过throughPoint的射线
    constants: [], // { id, type: 'angle'|'length'|'area', name, pointIds: [], value }
    expressions: [], // { id, parts: [{type: 'constant', name}|{type: 'operator', value: '='|'/'|'*'|':'|'+'|'-'|'div'|'^2'}], result: string }
    dragConstraints: [], // { id, pointId, lineId } - 拖动约束
    slidingConstraints: [], // { id, slidingPointId, constraintPointId } - 滑动点约束，防止滑动点超出约束点
    config: {
      pointSize: 8,
      lineWidth: 2
    }
  });

  const [saving, setSaving] = useState(false);

  // 状态管理（按钮/多视图）
  const [modelStates, setModelStates] = useState([]); // 所有状态列表
  const [currentStateId, setCurrentStateId] = useState(null); // 当前选中的状态ID（null = 母版）
  const [masterData, setMasterData] = useState(null); // 母版数据（geometryData作为母版）

  // 撤回/重做历史记录
  const [history, setHistory] = useState([]); // 历史记录栈
  const [historyIndex, setHistoryIndex] = useState(-1); // 当前历史记录索引
  const isUndoRedoRef = useRef(false); // 标记是否正在执行撤回/重做操作

  // 工作区默认设置（从后端加载）
  const [workspaceDefaults, setWorkspaceDefaults] = useState({
    commonColors: ['#FF0000', '#00FF00', '#0000FF'],  // 常用色1、2、3
    shadowColor: 'rgba(128, 128, 128, 0.15)',         // 固定阴影色
    defaultFontSizes: {
      lineLabel: 16,
      areaLabel: 18,
      pointLabel: 16
    }
  });

  // 将十六进制颜色转换为 rgba 格式（带透明度）
  const hexToRgba = useCallback((hex, alpha = 0.15) => {
    const r = parseInt(hex.slice(1, 3), 16);
    const g = parseInt(hex.slice(3, 5), 16);
    const b = parseInt(hex.slice(5, 7), 16);
    return `rgba(${r}, ${g}, ${b}, ${alpha})`;
  }, []);

  // 填充颜色选项（基于工作区设置）
  const FILL_COLORS = useMemo(() => [
    { name: '常用色1', value: hexToRgba(workspaceDefaults.commonColors[0], 0.15), hex: workspaceDefaults.commonColors[0] },
    { name: '常用色2', value: hexToRgba(workspaceDefaults.commonColors[1], 0.15), hex: workspaceDefaults.commonColors[1] },
    { name: '常用色3', value: hexToRgba(workspaceDefaults.commonColors[2], 0.15), hex: workspaceDefaults.commonColors[2] },
    { name: '阴影', value: workspaceDefaults.shadowColor, hex: '#808080' }
  ], [workspaceDefaults.commonColors, workspaceDefaults.shadowColor, hexToRgba]);

  // 线段颜色选项（基于工作区设置）
  const LINE_COLORS = useMemo(() => [
    { name: '常用色1', value: workspaceDefaults.commonColors[0] },
    { name: '常用色2', value: workspaceDefaults.commonColors[1] },
    { name: '常用色3', value: workspaceDefaults.commonColors[2] },
    { name: '阴影', value: '#808080' }
  ], [workspaceDefaults.commonColors]);

  // 加载工作区默认设置
  useEffect(() => {
    const loadSettings = async () => {
      try {
        const settings = await settingsAPI.getWorkspaceDefaults();
        setWorkspaceDefaults(settings);
      } catch (err) {
        console.error('加载设置失败:', err);
        // 使用默认值，不显示错误提示
      }
    };
    loadSettings();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 加载章节列表
  useEffect(() => {
    const loadChapters = async () => {
      try {
        const data = await chapterAPI.getAll();
        setChapters(data);
      } catch (err) {
        console.error('加载章节失败:', err);
        toast.error('加载章节失败: ' + err.message);
      }
    };
    loadChapters();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 编辑模式：加载现有模型和状态
  useEffect(() => {
    if (id) {
      const loadModel = async () => {
        try {
          const model = await modelAPI.getById(id);

          // 检查是否为特殊模型，禁止编辑
          if (model.is_special === 1) {
            toast.error('特殊模型不允许编辑！');
            navigate(-1);
            return;
          }

          setFormData({
            chapter_id: model.chapter_id,
            title: model.title,
            order_num: model.order_num,
            is_special: model.is_special === 1,
            template_path: model.template_path || ''
          });
          const parsedData = JSON.parse(model.canvas_data);
          setGeometryData(parsedData);
          setMasterData(parsedData); // 设置母版数据

          // 加载模型的所有状态
          try {
            const states = await stateAPI.getModelStates(id);
            setModelStates(states);
          } catch (err) {
            console.error('加载状态失败:', err);
            toast.warning('加载状态失败: ' + err.message);
            // 不阻塞主流程
          }
        } catch (err) {
          toast.error('加载模型失败: ' + err.message);
        }
      };
      loadModel();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [id]);

  // 自动保存（每30秒）
  useEffect(() => {
    if (!id) return; // 只有编辑模式才自动保存

    const autoSaveInterval = setInterval(async () => {
      // 静默保存，不显示过多提示
      try {
        await handleSave(true); // true 表示静默保存
      } catch (err) {
        console.error('自动保存失败:', err);
      }
    }, 30000); // 30秒

    return () => clearInterval(autoSaveInterval);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [id, geometryData, formData]);

  // 记录历史（当 geometryData 变化时）
  useEffect(() => {
    // 如果是撤回/重做操作导致的变化，不记录历史
    if (isUndoRedoRef.current) {
      isUndoRedoRef.current = false;
      return;
    }

    // 如果是初始加载（history为空），记录初始状态
    if (history.length === 0) {
      setHistory([JSON.parse(JSON.stringify(geometryData))]);
      setHistoryIndex(0);
      return;
    }

    // 检查是否真的有变化（避免重复记录）
    const lastState = history[historyIndex];
    if (lastState && JSON.stringify(lastState) === JSON.stringify(geometryData)) {
      return;
    }

    // 记录新的历史状态
    const newHistory = history.slice(0, historyIndex + 1);
    newHistory.push(JSON.parse(JSON.stringify(geometryData)));

    // 限制历史记录数量（最多保留50条）
    const maxHistory = 50;
    if (newHistory.length > maxHistory) {
      newHistory.shift();
      setHistory(newHistory);
      setHistoryIndex(newHistory.length - 1);
    } else {
      setHistory(newHistory);
      setHistoryIndex(newHistory.length - 1);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [geometryData]);

  // 撤回函数
  const handleUndo = () => {
    if (historyIndex > 0) {
      isUndoRedoRef.current = true;
      const newIndex = historyIndex - 1;
      setHistoryIndex(newIndex);
      setGeometryData(JSON.parse(JSON.stringify(history[newIndex])));
      toast.info('已撤回');
    } else {
      toast.warning('没有可撤回的操作');
    }
  };

  // 重做函数
  const handleRedo = () => {
    if (historyIndex < history.length - 1) {
      isUndoRedoRef.current = true;
      const newIndex = historyIndex + 1;
      setHistoryIndex(newIndex);
      setGeometryData(JSON.parse(JSON.stringify(history[newIndex])));
      toast.info('已重做');
    } else {
      toast.warning('没有可重做的操作');
    }
  };

  // Ctrl+S 保存快捷键 和 Ctrl+Z 撤回快捷键
  useEffect(() => {
    const handleKeyDown = (e) => {
      // Ctrl+S 保存
      if ((e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'S')) {
        e.preventDefault();
        e.stopPropagation();
        handleSave();
        return false;
      }

      // Ctrl+Z 撤回
      if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
        e.preventDefault();
        e.stopPropagation();
        handleUndo();
        return false;
      }

      // Ctrl+Shift+Z 或 Ctrl+Y 重做
      if ((e.ctrlKey || e.metaKey) && ((e.key === 'z' && e.shiftKey) || e.key === 'y')) {
        e.preventDefault();
        e.stopPropagation();
        handleRedo();
        return false;
      }
    };

    // 使用 capture 阶段确保优先捕获事件
    window.addEventListener('keydown', handleKeyDown, true);
    return () => window.removeEventListener('keydown', handleKeyDown, true);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [id, geometryData, formData, historyIndex, history]);

  // 绘制画布
  // 自动更新垂足点（当相关点移动时）
  useEffect(() => {
    if (geometryData.perpendiculars && geometryData.perpendiculars.length > 0) {
      // 更新所有垂足点（不传入draggedPointId，更新所有）
      const updatedPoints = updatePerpendicularFootPoints(geometryData.points, geometryData.perpendiculars);
      
      // 检查是否有垂足点位置发生变化
      let hasChanges = false;
      if (updatedPoints.length !== geometryData.points.length) {
        hasChanges = true;
      } else {
        for (let i = 0; i < updatedPoints.length; i++) {
          const newPoint = updatedPoints[i];
          const oldPoint = geometryData.points.find(p => p.id === newPoint.id);
          if (!oldPoint) {
            hasChanges = true;
            break;
          }
          // 只检查垂足点
          if (newPoint.isFootPoint && (oldPoint.x !== newPoint.x || oldPoint.y !== newPoint.y)) {
            hasChanges = true;
            break;
          }
        }
      }
      
      if (hasChanges) {
        setGeometryData(prev => ({
          ...prev,
          points: updatedPoints
        }));
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [geometryData.perpendiculars, geometryData.points]);

  // 自动更新交点
  useEffect(() => {
    const hasGeometry = geometryData.lines.length >= 2 ||
                        geometryData.parallels?.length > 0 ||
                        geometryData.rays?.length > 0;

    if (hasGeometry) {
      const updatedPoints = updateIntersectionPoints(
        geometryData.points,
        geometryData.lines,
        geometryData.parallels || [],
        geometryData.rays || []
      );
      if (updatedPoints.length !== geometryData.points.length ||
        updatedPoints.some((p, i) => {
          const oldP = geometryData.points[i];
          return oldP && p.isIntersection && (oldP.x !== p.x || oldP.y !== p.y);
        })) {
        setGeometryData(prev => ({
          ...prev,
          points: updatedPoints
        }));
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [geometryData.lines, geometryData.rays, geometryData.parallels, geometryData.rays, geometryData.points.filter(p => !p.isIntersection)]);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    drawCanvas(ctx);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [geometryData, selectedItem, selectedPointsForConstant]);

  const drawCanvas = (ctx) => {
    const { width, height } = ctx.canvas;

    // 清空画布
    ctx.clearRect(0, 0, width, height);

    // 绘制填充的面积区域（在所有其他元素之前）
    geometryData.constants?.forEach(constant => {
      if (constant.type === 'area' && constant.fill && constant.fillColor && constant.pointIds && constant.pointIds.length >= 3) {
        const points = constant.pointIds.map(id =>
          geometryData.points.find(p => p.id === id)
        ).filter(Boolean);

        if (points.length >= 3) {
          ctx.save();
          ctx.fillStyle = constant.fillColor;
          ctx.beginPath();
          ctx.moveTo(points[0].x, points[0].y);
          for (let i = 1; i < points.length; i++) {
            ctx.lineTo(points[i].x, points[i].y);
          }
          ctx.closePath();
          ctx.fill();
          ctx.restore();
        }
      }
    });

    // 绘制连线（使用统一工具函数，编辑模式）
    // 如果在滑动点编辑模式，只显示选中的线段以及不重合的线段
    geometryData.lines.forEach(line => {
      // 如果在滑动点编辑模式
      if (pointOnLineMode?.lineId && pointOnLineMode.type === 'slide') {
        const selectedLine = geometryData.lines.find(l => l.id === pointOnLineMode.lineId);

        if (selectedLine && line.id !== selectedLine.id) {
          // 检查两条线段是否重合或共线
          const line1Start = geometryData.points.find(p => p.id === selectedLine.startPointId);
          const line1End = geometryData.points.find(p => p.id === selectedLine.endPointId);
          const line2Start = geometryData.points.find(p => p.id === line.startPointId);
          const line2End = geometryData.points.find(p => p.id === line.endPointId);

          if (line1Start && line1End && line2Start && line2End) {
            // 检查是否共享端点（有可能共线）
            const sharePoint =
              line1Start.id === line2Start.id || line1Start.id === line2End.id ||
              line1End.id === line2Start.id || line1End.id === line2End.id;

            if (sharePoint) {
              // 检查是否共线：计算向量叉积
              const v1 = { x: line1End.x - line1Start.x, y: line1End.y - line1Start.y };
              const v2 = { x: line2End.x - line2Start.x, y: line2End.y - line2Start.y };
              const crossProduct = Math.abs(v1.x * v2.y - v1.y * v2.x);

              // 如果叉积接近0，说明共线，跳过绘制
              if (crossProduct < 1) {
                return; // 不绘制这条线
              }
            }
          }
        }
      }

      drawLineById(ctx, geometryData.points, line, { offsetX: 0, offsetY: 0 }, true);
    });

    // 绘制垂线（如果有）
    if (geometryData.perpendiculars) {
      geometryData.perpendiculars.forEach(perpendicular => {
        // 如果样式为隐藏，则跳过绘制
        if (perpendicular.style === 'hidden') return;

        drawPerpendicularById(ctx, geometryData.points, perpendicular, { offsetX: 0, offsetY: 0 }, {
          drawExtension: true,
          extensionStyle: { style: 'dashed', color: '#999', width: 1 },
          perpendicularStyle: {
            style: perpendicular.style || 'dashed',
            color: perpendicular.color || '#666',
            width: perpendicular.width || 2
          },
          drawFootMark: perpendicular.showFoot !== false, // 默认显示垂足标记
          footMarkSize: 14
        });
      });
    }

    // 绘制平行线（如果有）
    if (geometryData.parallels) {
      geometryData.parallels.forEach(parallel => {
        // 如果样式为隐藏，则跳过绘制
        if (parallel.style === 'hidden') return;

        const fromPoint = geometryData.points.find(p => p.id === parallel.fromPointId);
        const lineStart = geometryData.points.find(p => p.id === parallel.toLineStartId);
        const lineEnd = geometryData.points.find(p => p.id === parallel.toLineEndId);

        if (fromPoint && lineStart && lineEnd) {
          // 计算平行线的方向向量（与目标线段相同）
          const dx = lineEnd.x - lineStart.x;
          const dy = lineEnd.y - lineStart.y;
          const length = Math.sqrt(dx * dx + dy * dy);

          // 计算单位方向向量
          const unitDx = dx / length;
          const unitDy = dy / length;

          // 延伸到画布边界外（使用一个足够大的距离）
          const extensionDistance = 5000; // 足够大的距离，确保延伸到画布外

          // 计算平行线的两个端点（从fromPoint出发，沿平行方向延伸）
          const parallelStart = {
            x: fromPoint.x - unitDx * extensionDistance,
            y: fromPoint.y - unitDy * extensionDistance
          };
          const parallelEnd = {
            x: fromPoint.x + unitDx * extensionDistance,
            y: fromPoint.y + unitDy * extensionDistance
          };

          // 使用普通线段的绘制方式
          drawLine(ctx, parallelStart, parallelEnd, {
            style: parallel.style || 'solid',
            color: parallel.color || DRAWING_STYLES.line.color,
            width: parallel.width || DRAWING_STYLES.line.width,
            label: parallel.label,
            labelOffset: parallel.labelOffset
          }, { offsetX: 0, offsetY: 0 }, true);
        }
      });
    }

    // 绘制射线（如果有）
    if (geometryData.rays) {
      geometryData.rays.forEach(ray => {
        // 如果样式为隐藏，则跳过绘制
        if (ray.style === 'hidden') return;

        drawRayById(ctx, geometryData.points, ray, { offsetX: 0, offsetY: 0 }, true);
      });
    }



    // 绘制标签（使用统一工具函数）
    geometryData.labels.forEach(label => {
      const isSelected = label.id === selectedItem?.id;
      // 如果是面积标签，从关联的常量获取符号转换设置
      let enableSymbolConversion = true;
      if (label.isAreaLabel && label.linkedConstantId) {
        const constant = geometryData.constants?.find(c => c.id === label.linkedConstantId);
        if (constant) {
          enableSymbolConversion = constant.enableSymbolConversion !== false;
        }
      }
      drawLabel(ctx, { ...label, enableSymbolConversion }, { offsetX: 0, offsetY: 0 }, isSelected);
    });

    // 绘制点（使用统一工具函数）
    geometryData.points.forEach(point => {
      // 工作空间：所有点都显示，不可拖动的点显示为灰色
      const isSelected = point.id === selectedItem?.id;
      const isSelectedForConstant = selectedPointsForConstant.includes(point.id);

      // 如果点被隐藏，只绘制标签，不绘制点本身
      if (point.hidden) {
        // 只绘制标签，使用相对偏移量（与 drawPoint 函数一致）
        if (point.label) {
          ctx.save();
          const labelOffset = point.labelOffset || { x: 0, y: 0 };
          ctx.fillStyle = DRAWING_STYLES.label.color;
          ctx.font = DRAWING_STYLES.label.italicFont;
          ctx.fillText(
            point.label,
            point.x + DRAWING_STYLES.label.offsetX + labelOffset.x,
            point.y + DRAWING_STYLES.label.offsetY + labelOffset.y
          );
          ctx.restore();
        }
      } else {
        // 绘制基础顶点（drawPoint会自动绘制点的label属性）
        drawPoint(ctx, point, { offsetX: 0, offsetY: 0 }, isSelected);

        // 绘制常量选择状态（橙色外圈）
        if (isSelectedForConstant) {
          const size = geometryData.config.pointSize;
          ctx.strokeStyle = '#FF9500';
          ctx.lineWidth = 4;
          ctx.beginPath();
          ctx.arc(point.x, point.y, size + 4, 0, Math.PI * 2);
          ctx.stroke();
        }
      }
    });
  };

  // ========== 几何计算辅助函数（使用统一工具） ==========
  // 注意：getDistance 和 calculateLineIntersection 已从 utils 导入
  // updateIntersectionPoints 也已从 utils 导入

  // 格式化常量名称显示（将面积常量转换为 S + 下标形式）
  const formatConstantName = (constant) => {
    if (constant.type === 'area') {
      // 移除名称开头的所有 S（无论大小写）
      const content = constant.name.replace(/^[Ss]+/g, '');
      return (
        <span className="constant-name-formatted">
          S<sub>{content}</sub>
        </span>
      );
    }
    return constant.name;
  };

  // 根据常量名获取常量值（使用utils工具函数）
  const getConstantValue = (name) => {
    return getConstantValueByName(name, geometryData.constants, geometryData.points);
  };

  // 渲染表达式公式（使用 utils 中的解析函数）
  const renderExpressionFormula = (expression) => {
    const parsed = parseExpressionForRender(expression, geometryData.constants);

    return parsed.map((element, idx) => {
      if (element.type === 'fraction') {
        // 渲染分式
        const renderParts = (parts) => {
          return parts.map((p, partIdx) => {
            if (p.type === 'constant') {
              // 查找对应的常量，获取符号转换设置
              const constant = geometryData.constants.find(c => c.name === p.name);
              const enableConversion = constant?.enableSymbolConversion !== false;
              
              if (p.isArea) {
                const convertedName = convertToMathSymbols(p.displayName, enableConversion);
                return <React.Fragment key={partIdx}>S<sub>{convertedName}</sub></React.Fragment>;
              }
              const convertedName = convertToMathSymbols(p.name, enableConversion);
              return <React.Fragment key={partIdx}>{convertedName}</React.Fragment>;
            } else if (p.type === 'number') {
              return <React.Fragment key={partIdx}>{p.value}</React.Fragment>;
            } else if (p.type === 'operator') {
              return <React.Fragment key={partIdx}>{p.symbol}</React.Fragment>;
            } else if (p.type === 'bracket') {
              return <React.Fragment key={partIdx}>{p.value}</React.Fragment>;
            }
            return null;
          });
        };

        return (
          <span key={idx} className="fraction">
            <span className="fraction-numerator">
              {renderParts(element.numerator)}
            </span>
            <span className="fraction-line"></span>
            <span className="fraction-denominator">
              {renderParts(element.denominator)}
            </span>
          </span>
        );
      } else if (element.type === 'constant') {
        // 查找对应的常量，获取符号转换设置
        const constant = geometryData.constants.find(c => c.name === element.name);
        const enableConversion = constant?.enableSymbolConversion !== false;
        
        if (element.isArea) {
          const convertedName = convertToMathSymbols(element.displayName, enableConversion);
          return <span key={idx}>S<sub>{convertedName}</sub></span>;
        }
        const convertedName = convertToMathSymbols(element.name, enableConversion);
        return <span key={idx}>{convertedName}</span>;
      } else if (element.type === 'number') {
        return <span key={idx}>{element.value}</span>;
      } else if (element.type === 'operator') {
        const className = `operator-${element.value}`;
        return <span key={idx} className={className}>{element.symbol}</span>;
      } else if (element.type === 'bracket') {
        return <span key={idx}>{element.value}</span>;
      }
      return null;
    });
  };

  // 获取画布坐标（使用utils工具函数）
  const getCanvasCoords = (e) => {
    return getCanvasCoordinates(e, canvasRef.current);
  };

  // 查找点击的元素（使用统一工具函数）
  const findClickedItemLocal = (x, y) => {
    const ctx = canvasRef.current.getContext('2d');
    const LABEL_CLICK_THRESHOLD = 10; // 点击容差（像素）

    // 检查点的标签（优先级最高，在检查点本身之前）
    for (const point of geometryData.points) {
      if (point.label) {
        ctx.font = DRAWING_STYLES.label.italicFont;
        const metrics = ctx.measureText(point.label);

        // 使用 DRAWING_STYLES 的偏移量
        const labelOffset = point.labelOffset || { x: 0, y: 0 };

        const labelX = point.x + DRAWING_STYLES.label.offsetX + labelOffset.x;
        const labelY = point.y + DRAWING_STYLES.label.offsetY + labelOffset.y;
        const labelWidth = metrics.width;
        const labelHeight = DRAWING_STYLES.label.fontSize;

        if (x >= labelX - LABEL_CLICK_THRESHOLD &&
          x <= labelX + labelWidth + LABEL_CLICK_THRESHOLD &&
          y <= labelY + LABEL_CLICK_THRESHOLD &&
          y >= labelY - labelHeight - LABEL_CLICK_THRESHOLD) {
          return {
            type: 'point-label',
            item: point,
            isPointLabel: true
          };
        }
      }
    }

    // 检查点（优先级次之）- 使用utils中的函数
    const clickedPoint = findClickedPoint(x, y, geometryData.points, geometryData.config.pointSize, 5);
    if (clickedPoint) {
      return { type: 'point', item: clickedPoint };
    }

    // 检查独立标签（增加点击容差，使标签更容易被选中和拖动）
    for (const label of geometryData.labels) {
      ctx.font = `${label.fontSize || 16}px Times New Roman`;
      const metrics = ctx.measureText(label.text);
      const direction = label.direction || 'right';

      // 根据方向计算标签的实际显示位置
      let labelX = label.x;
      let labelY = label.y;
      const offsetX = 15;
      const offsetY = -10;

      switch (direction) {
        case 'right':
          labelX = label.x + offsetX;
          labelY = label.y + offsetY;
          break;
        case 'left':
          labelX = label.x - offsetX - metrics.width;
          labelY = label.y + offsetY;
          break;
        case 'top':
          labelX = label.x - metrics.width / 2;
          labelY = label.y - label.fontSize - offsetX;
          break;
        case 'bottom':
          labelX = label.x - metrics.width / 2;
          labelY = label.y + offsetX;
          break;
      }

      // 扩大点击区域，增加容差
      const labelWidth = metrics.width;
      const labelHeight = label.fontSize || 16;

      if (x >= labelX - LABEL_CLICK_THRESHOLD &&
        x <= labelX + labelWidth + LABEL_CLICK_THRESHOLD &&
        y <= labelY + LABEL_CLICK_THRESHOLD &&
        y >= labelY - labelHeight - LABEL_CLICK_THRESHOLD) {
        return { type: 'label', item: label };
      }
    }

    // 检查线段标签
    const LABEL_CLICK_THRESHOLD_LINE = 10;
    for (const line of geometryData.lines) {
      if (!line.label || !line.label.trim()) continue;
      
      const startPoint = geometryData.points.find(p => p.id === line.startPointId);
      const endPoint = geometryData.points.find(p => p.id === line.endPointId);
      
      if (!startPoint || !endPoint) continue;
      
      // 计算线段中点
      const midX = (startPoint.x + endPoint.x) / 2;
      const midY = (startPoint.y + endPoint.y) / 2;
      
      // 计算线段方向和垂直偏移
      const dx = endPoint.x - startPoint.x;
      const dy = endPoint.y - startPoint.y;
      const length = Math.sqrt(dx * dx + dy * dy);
      
      // 标签偏移距离（垂直于线段）
      const defaultLabelOffset = 15;
      
      // 垂直向量（向上）
      const perpX = -(dy / length) * defaultLabelOffset;
      const perpY = (dx / length) * defaultLabelOffset;
      
      // 应用自定义偏移
      const customOffset = line.labelOffset || { x: 0, y: 0 };
      
      const labelX = midX + perpX + customOffset.x;
      const labelY = midY + perpY + customOffset.y;
      
      // 估算标签宽度（粗略计算）
      const ctx = canvasRef.current?.getContext('2d');
      if (ctx) {
        ctx.save();
        ctx.font = 'italic 16px Arial';
        const metrics = ctx.measureText(line.label);
        ctx.restore();
        
        const labelWidth = metrics.width;
        const labelHeight = 16;
        
        // 检查点击是否在标签区域内（居中对齐）
        if (x >= labelX - labelWidth / 2 - LABEL_CLICK_THRESHOLD_LINE &&
            x <= labelX + labelWidth / 2 + LABEL_CLICK_THRESHOLD_LINE &&
            y >= labelY - labelHeight / 2 - LABEL_CLICK_THRESHOLD_LINE &&
            y <= labelY + labelHeight / 2 + LABEL_CLICK_THRESHOLD_LINE) {
          return { type: 'line-label', item: line };
        }
      }
    }

    // 检查垂线 - 使用utils中的函数
    const clickedPerpendicular = findClickedPerpendicular(x, y, geometryData.perpendiculars || [], geometryData.points, 8);
    if (clickedPerpendicular) {
      return clickedPerpendicular;
    }

    // 检查射线 - 使用utils中的函数
    const clickedRay = findClickedRay(x, y, geometryData.rays || [], geometryData.points, 8);
    if (clickedRay) {
      return clickedRay;
    }

    // 检查线条 - 使用utils中的函数
    const clickedLine = findClickedLine(x, y, geometryData.lines, geometryData.points, 8);
    if (clickedLine) {
      return clickedLine;
    }

    return null;
  };

  // 查找点击的线段（直接使用utils中的函数）
  const findClickedLineLocal = (x, y) => {
    return findClickedLine(x, y, geometryData.lines, geometryData.points, 8);
  };

  // 查找点击的点（直接使用utils中的函数）
  const findClickedPointLocal = (x, y) => {
    const clickedPoint = findClickedPoint(x, y, geometryData.points, geometryData.config.pointSize, 5);
    if (clickedPoint) {
      return { type: 'point', item: clickedPoint };
    }
    return null;
  };

  // 鼠标按下
  const handleMouseDown = async (e) => {
    // 如果处于添加约束模式，不处理其他逻辑
    if (addingConstraintMode) {
      return;
    }

    const coords = getCanvasCoords(e);

    // 如果在线上标点模式（编辑模式）
    if (currentTool === 'pointOnLine' && pointOnLineMode) {
      // 只能为选中的线段添加滑动点
      if (!selectedItem || selectedItem.type !== 'line') {
        toast.error('请先选中一条线段');
        return;
      }

      const line = selectedItem;
      const lineStart = geometryData.points.find(p => p.id === line.startPointId);
      const lineEnd = geometryData.points.find(p => p.id === line.endPointId);

      if (!lineStart || !lineEnd) return;

      // 计算点击位置在线段上的投影
      const lineLength = getDistance(lineStart, lineEnd);
      const t = Math.max(0, Math.min(1,
        ((coords.x - lineStart.x) * (lineEnd.x - lineStart.x) +
          (coords.y - lineStart.y) * (lineEnd.y - lineStart.y)) / (lineLength * lineLength)
      ));

      const projectionX = lineStart.x + t * (lineEnd.x - lineStart.x);
      const projectionY = lineStart.y + t * (lineEnd.y - lineStart.y);

      // 创建新点
      const newPoint = {
        id: `point_${Date.now()}`,
        x: projectionX,
        y: projectionY,
        label: '',
        color: '#007AFF',
        draggable: true
      };

      if (pointOnLineMode.type === 'fixed') {
        // 定点模式：固定在绝对坐标，不随线段拉伸改变
        // 询问用户选择固定到哪一端
        const startLabel = lineStart.label || `点${lineStart.id}`;
        const endLabel = lineEnd.label || `点${lineEnd.id}`;

        // 使用 setTimeout 延迟显示对话框，避免当前点击事件干扰
        const anchorChoice = await new Promise(resolve => {
          setTimeout(async () => {
            const result = await showSelect({
              title: '选择固定端点',
              message: '定点相对于哪个端点固定？',
              options: [
                { label: startLabel, value: 'start' },
                { label: endLabel, value: 'end' }
              ]
            });
            resolve(result);
          }, 100); // 延迟 100ms
        });

        if (!anchorChoice) {
          toast.info('取消添加定点');
          return;
        }

        // 保存相对于固定端点的偏移量
        const anchorPoint = anchorChoice === 'start' ? lineStart : lineEnd;
        newPoint.fixedToPoint = {
          lineId: line.id,
          anchorPointId: anchorPoint.id,
          offsetX: projectionX - anchorPoint.x,
          offsetY: projectionY - anchorPoint.y
        };
        newPoint.color = '#808080'; // 灰色（不可拖动）
        newPoint.draggable = false; // 不可拖动

        setGeometryData(prev => ({
          ...prev,
          points: [...prev.points, newPoint]
        }));

        toast.success(`添加定点（固定到${anchorChoice === 'start' ? startLabel : endLabel}）`);
      } else {
        // 滑动模式：点从属于线段，可以在线上滑动
        newPoint.constrainedToLine = {
          lineId: line.id,
          startPointId: line.startPointId,
          endPointId: line.endPointId,
          ratio: t
        };
        newPoint.color = '#007AFF'; // 蓝色

        setGeometryData(prev => ({
          ...prev,
          points: [...prev.points, newPoint]
        }));

        toast.success('添加滑动点');
      }
      return;
    }

    // 如果在平行线模式
    if (currentTool === 'parallel' && parallelMode) {
      // 选择起始点
      const clicked = findClickedItemLocal(coords.x, coords.y);
      if (clicked && clicked.type === 'point') {
        const fromPoint = clicked.item;

        // 使用 setTimeout 延迟显示输入框，避免当前点击事件干扰
        const lineLabel = await new Promise(resolve => {
          setTimeout(async () => {
            const result = await showDialog({
              title: '输入目标线段',
              message: '请输入线段两端点的标签（将添加平行线）',
              fields: [
                {
                  name: 'lineLabel',
                  label: '线段标签',
                  type: 'text',
                  placeholder: '例如：AB 或 BA',
                  required: true
                }
              ],
              confirmText: '确认',
              cancelText: '取消'
            });
            resolve(result?.lineLabel);
          }, 100); // 延迟 100ms
        });

        if (!lineLabel) {
          toast.info('取消添加平行线');
          return;
        }

        // 查找匹配的线段
        const targetLine = geometryData.lines.find(line => {
          const startPoint = geometryData.points.find(p => p.id === line.startPointId);
          const endPoint = geometryData.points.find(p => p.id === line.endPointId);

          if (!startPoint || !endPoint || !startPoint.label || !endPoint.label) {
            return false;
          }

          const label1 = startPoint.label + endPoint.label;
          const label2 = endPoint.label + startPoint.label;
          const inputLabel = lineLabel.trim().toUpperCase();

          return label1.toUpperCase() === inputLabel || label2.toUpperCase() === inputLabel;
        });

        if (!targetLine) {
          toast.error(`未找到线段 ${lineLabel}`);
          return;
        }

        // 创建平行线
        const newParallel = {
          id: `parallel_${Date.now()}`,
          fromPointId: fromPoint.id,
          toLineStartId: targetLine.startPointId,
          toLineEndId: targetLine.endPointId,
          style: 'solid',
          color: DRAWING_STYLES.line.color,
          width: DRAWING_STYLES.line.width
        };

        setGeometryData(prev => ({
          ...prev,
          parallels: [...(prev.parallels || []), newParallel]
        }));

        toast.success('平行线已添加');
      }
      return;
    }

    // 如果在垂线模式
    if (currentTool === 'perpendicular' && perpendicularMode) {
      // 选择起始点
      const clicked = findClickedItemLocal(coords.x, coords.y);
      if (clicked && clicked.type === 'point') {
        const fromPoint = clicked.item;

        // 使用 setTimeout 延迟显示输入框，避免当前点击事件干扰
        const lineLabel = await new Promise(resolve => {
          setTimeout(async () => {
            const result = await showDialog({
              title: '输入目标线段',
              message: '请输入线段两端点的标签',
              fields: [
                {
                  name: 'lineLabel',
                  label: '线段标签',
                  type: 'text',
                  placeholder: '例如：AB 或 BA',
                  required: true
                }
              ],
              confirmText: '确认',
              cancelText: '取消'
            });
            resolve(result?.lineLabel);
          }, 100); // 延迟 100ms
        });

        if (!lineLabel) {
          toast.info('取消添加垂线');
          return;
        }

        // 查找匹配的线段
        const targetLine = geometryData.lines.find(line => {
          const startPoint = geometryData.points.find(p => p.id === line.startPointId);
          const endPoint = geometryData.points.find(p => p.id === line.endPointId);

          if (!startPoint || !endPoint || !startPoint.label || !endPoint.label) {
            return false;
          }

          const label1 = startPoint.label + endPoint.label;
          const label2 = endPoint.label + startPoint.label;
          const inputLabel = lineLabel.trim().toUpperCase();

          return label1.toUpperCase() === inputLabel || label2.toUpperCase() === inputLabel;
        });

        if (!targetLine) {
          toast.error(`未找到线段 ${lineLabel}`);
          return;
        }

        // 获取线段的起点和终点
        const lineStart = geometryData.points.find(p => p.id === targetLine.startPointId);
        const lineEnd = geometryData.points.find(p => p.id === targetLine.endPointId);

        if (lineStart && lineEnd) {
          // 计算垂足位置
          const { foot, t } = calculatePerpendicularFoot(
            fromPoint,
            lineStart,
            lineEnd
          );

          // 创建垂足点（作为滑动点）
          const footPoint = {
            id: `foot_${Date.now()}`,
            x: foot.x,
            y: foot.y,
            label: '',
            color: '#999999',
            draggable: false,  // 垂足点不可拖动
            isFootPoint: true,  // 标记为垂足点
            hidden: false,  // 是否隐藏点（标签仍然显示）
            constrainedToLine: {
              startPointId: targetLine.startPointId,
              endPointId: targetLine.endPointId,
              ratio: t  // 不限制 ratio，允许超出线段范围
            }
          };

          // 创建垂线
          const newPerpendicular = {
            id: `perpendicular_${Date.now()}`,
            fromPointId: fromPoint.id,
            toLineStartId: targetLine.startPointId,
            toLineEndId: targetLine.endPointId,
            footPointId: footPoint.id,
            style: 'dashed', // 实线/虚线/隐藏
            width: 2, // 线宽
            showFoot: true // 是否显示垂足标记
          };

          setGeometryData(prev => ({
            ...prev,
            points: [...prev.points, footPoint],
            perpendiculars: [...(prev.perpendiculars || []), newPerpendicular]
          }));

          toast.success(`已添加从 ${fromPoint.label || '点'} 到 ${lineLabel} 的垂线`);
        }
      }
      return;
    }

    // 如果在常量选择模式，只处理常量选择
    if (currentTool === 'constant' && constantMode) {
      const clicked = findClickedItemLocal(coords.x, coords.y);
      // 支持点击点本身或点的标签来选择点（包括垂点、定点、滑动点等所有类型的点）
      if (clicked && (clicked.type === 'point' || clicked.type === 'point-label')) {
        const pointId = clicked.item.id;

        // 检查是否已经选中
        if (selectedPointsForConstant.includes(pointId)) {
          // 取消选中
          setSelectedPointsForConstant(selectedPointsForConstant.filter(id => id !== pointId));
        } else {
          // 添加选中
          setSelectedPointsForConstant([...selectedPointsForConstant, pointId]);
        }
      }
      return; // 重要：在常量模式下，不执行后续的其他工具逻辑
    }

    if (currentTool === 'select') {
      const clicked = findClickedItemLocal(coords.x, coords.y);
      if (clicked) {
        // 保存选中项，包括类型信息
        setSelectedItem({ ...clicked.item, type: clicked.type });
        // 只有当点可拖动时才允许拖动
        if (clicked.type === 'point' && clicked.item.draggable === false) {
          // 不可拖动的点，不设置 dragging
          setDragging(null);
        } else if (clicked.type === 'line') {
          // 线段不能拖动
          setDragging(null);
        } else {
          // 如果是标签或点标签或线段标签，保存初始拖拽位置
          if (clicked.type === 'label' || clicked.type === 'point-label' || clicked.type === 'line-label') {
            setDragging({
              ...clicked,
              startX: coords.x,
              startY: coords.y,
              startOffset: clicked.item.labelOffset || { x: 0, y: 0 }
            });
          } else {
            setDragging(clicked);
          }
        }
      } else {
        setSelectedItem(null);
      }
    } else if (currentTool === 'point') {
      // 添加新点
      const newPoint = {
        id: `point_${Date.now()}`,
        x: coords.x,
        y: coords.y,
        label: '',
        color: '#007AFF',  // 默认蓝色（可拖动）
        draggable: true  // 默认可拖动
      };
      setGeometryData(prev => ({
        ...prev,
        points: [...prev.points, newPoint]
      }));
    } else if (currentTool === 'line') {
      // 连线工具：点击点来创建连线
      const clicked = findClickedItemLocal(coords.x, coords.y);
      if (clicked && clicked.type === 'point') {
        if (!selectedItem) {
          // 第一次点击：选中起点
          setSelectedItem(clicked.item);
        } else if (selectedItem.id !== clicked.item.id) {
          // 第二次点击：创建连线
          const newLine = {
            id: `line_${Date.now()}`,
            startPointId: selectedItem.id,
            endPointId: clicked.item.id,
            style: 'solid',
            color: '#333',
            width: 2
          };
          setGeometryData(prev => ({
            ...prev,
            lines: [...prev.lines, newLine]
          }));
          setSelectedItem(null);
        } else {
          // 点击同一个点：取消选择
          setSelectedItem(null);
        }
      }
    } else if (currentTool === 'ray') {
      // 射线工具：点击两个点来创建射线（从第一个点经过第二个点）
      const clicked = findClickedItemLocal(coords.x, coords.y);
      if (clicked && clicked.type === 'point') {
        if (!selectedItem) {
          // 第一次点击：选中起点
          setSelectedItem(clicked.item);
        } else if (selectedItem.id !== clicked.item.id) {
          // 第二次点击：创建射线
          const newRay = {
            id: `ray_${Date.now()}`,
            startPointId: selectedItem.id,
            throughPointId: clicked.item.id,
            style: 'solid',
            color: '#333',
            width: 2
          };
          setGeometryData(prev => ({
            ...prev,
            rays: [...(prev.rays || []), newRay]
          }));
          setSelectedItem(null);
          toast.success('射线已添加');
        } else {
          // 点击同一个点：取消选择
          setSelectedItem(null);
        }
      }
    }
  };

  // 鼠标移动
  const handleMouseMove = (e) => {
    if (!dragging) return;

    let coords = getCanvasCoords(e);

    // 处理标签拖动（优先处理）
    if (dragging.type === 'label') {
      // 面积标签不允许手动拖动
      if (dragging.item.isAreaLabel) {
        return;
      }

      // 计算鼠标移动的距离
      const deltaX = coords.x - dragging.startX;
      const deltaY = coords.y - dragging.startY;

      // 更新标签的相对偏移（在初始偏移基础上加上移动距离）
      const newOffset = {
        x: dragging.startOffset.x + deltaX,
        y: dragging.startOffset.y + deltaY
      };

      setGeometryData(prev => ({
        ...prev,
        labels: prev.labels.map(l =>
          l.id === dragging.item.id ? {
            ...l,
            labelOffset: newOffset
          } : l
        )
      }));

      return;
    }

    // 处理点标签拖动
    if (dragging.type === 'point-label') {
      // 计算鼠标移动的距离
      const deltaX = coords.x - dragging.startX;
      const deltaY = coords.y - dragging.startY;

      // 更新点标签的相对偏移（在初始偏移基础上加上移动距离）
      const newOffset = {
        x: dragging.startOffset.x + deltaX,
        y: dragging.startOffset.y + deltaY
      };

      setGeometryData(prev => ({
        ...prev,
        points: prev.points.map(p =>
          p.id === dragging.item.id ? {
            ...p,
            labelOffset: newOffset
          } : p
        )
      }));

      return;
    }

    // 处理线段标签拖动
    if (dragging.type === 'line-label') {
      // 计算鼠标移动的距离
      const deltaX = coords.x - dragging.startX;
      const deltaY = coords.y - dragging.startY;

      // 更新线段标签的相对偏移（在初始偏移基础上加上移动距离）
      const newOffset = {
        x: dragging.startOffset.x + deltaX,
        y: dragging.startOffset.y + deltaY
      };

      setGeometryData(prev => ({
        ...prev,
        lines: prev.lines.map(l =>
          l.id === dragging.item.id ? {
            ...l,
            labelOffset: newOffset
          } : l
        )
      }));

      return;
    }

    if (dragging.type === 'point') {
      const draggedPoint = dragging.item;

      // 检查点是否受限于线段（滑动点）
      if (draggedPoint.constrainedToLine) {
        setGeometryData(prev => {
          const { startPointId, endPointId } = draggedPoint.constrainedToLine;
          let startPoint = prev.points.find(p => p.id === startPointId);
          let endPoint = prev.points.find(p => p.id === endPointId);

          if (!startPoint || !endPoint) return prev;

          let updatedPoints = [...prev.points];

          // 检查这个滑动点是否是某个垂线的垂足点
          const isFootPoint = prev.perpendiculars?.some(perp => perp.footPointId === draggedPoint.id);

          if (isFootPoint) {
            // 如果是垂足点，不允许手动拖动，而是保持垂直关系
            // 垂足点的位置应该由起始点和目标线段自动计算
            return prev;
          }

          // 首先应用拖动约束
          const constrainedCoords = applyDragConstraints(
            draggedPoint,
            coords,
            prev.dragConstraints || [],
            prev.lines,
            prev.points
          );

          // 使用工具函数计算约束后的位置在滑动线段上的投影
          const projection = projectPointOnLine(constrainedCoords, startPoint, endPoint);
          let finalRatio = projection.t;

          // 碰撞检测：找到同一线段上的其他点，限制滑动范围
          const pointsOnSameLine = updatedPoints.filter(p => {
            if (p.id === draggedPoint.id) return false; // 排除自己

            // 检查是否在同一线段上
            if (p.constrainedToLine &&
              p.constrainedToLine.startPointId === draggedPoint.constrainedToLine.startPointId &&
              p.constrainedToLine.endPointId === draggedPoint.constrainedToLine.endPointId) {
              return true;
            }

            // 检查端点
            if (p.id === startPointId || p.id === endPointId) {
              return true;
            }

            return false;
          });

          // 计算每个点的 ratio
          const pointRatios = pointsOnSameLine.map(p => {
            if (p.id === startPointId) return 0;
            if (p.id === endPointId) return 1;
            return p.constrainedToLine?.ratio || 0;
          }).sort((a, b) => a - b);

          // 找到当前滑动点应该在的区间
          if (pointRatios.length > 0) {
            // 找到最接近的左右边界
            let leftBound = 0;
            let rightBound = 1;

            for (const ratio of pointRatios) {
              if (ratio < finalRatio && ratio > leftBound) {
                leftBound = ratio;
              }
              if (ratio > finalRatio && ratio < rightBound) {
                rightBound = ratio;
              }
            }

            // 限制在边界内，留出一点缓冲空间（0.001）
            const buffer = 0.001;
            finalRatio = Math.max(leftBound + buffer, Math.min(rightBound - buffer, finalRatio));
          }

          // 应用滑动点约束：防止滑动点超出约束点
          finalRatio = applySlidingConstraints(
            draggedPoint,
            finalRatio,
            prev.slidingConstraints || [],
            updatedPoints
          );

          // 根据最终 ratio 重新计算位置
          const finalX = startPoint.x + finalRatio * (endPoint.x - startPoint.x);
          const finalY = startPoint.y + finalRatio * (endPoint.y - startPoint.y);

          // 更新被拖动的滑动点
          updatedPoints = updatedPoints.map(p =>
            p.id === draggedPoint.id ? {
              ...p,
              x: finalX,
              y: finalY,
              constrainedToLine: { ...p.constrainedToLine, ratio: finalRatio }
            } : p
          );

          // 更新所有依赖于这个滑动点的其他滑动点
          updatedPoints = updateSlidingPoints(updatedPoints, draggedPoint.id);

          // 更新所有交点位置
          const pointsWithUpdatedIntersections = updateIntersectionPoints(
            updatedPoints,
            prev.lines,
            prev.parallels || [],
            prev.rays || []
          );

          // 更新所有面积标签的位置
          const updatedLabels = prev.labels.map(label => {
            if (label.isAreaLabel) {
              const constant = prev.constants.find(c => c.id === label.linkedConstantId);
              if (constant && constant.pointIds) {
                const allPoints = constant.pointIds.map(id =>
                  pointsWithUpdatedIntersections.find(p => p.id === id)
                ).filter(Boolean);

                if (allPoints.length > 0) {
                  let sumX = 0, sumY = 0;
                  allPoints.forEach(p => {
                    sumX += p.x;
                    sumY += p.y;
                  });
                  return {
                    ...label,
                    x: sumX / allPoints.length,
                    y: sumY / allPoints.length
                  };
                }
              }
            }
            return label;
          });

          return {
            ...prev,
            points: pointsWithUpdatedIntersections,
            labels: updatedLabels
          };
        });
        setSelectedItem(prev => prev ? { ...prev, x: coords.x, y: coords.y } : prev);
      } else {
        // 普通点，自由移动
        setGeometryData(prev => {
          // Shift键约束：如果按住Shift，且该点是某条线段的端点，限制为水平或垂直移动
          let finalCoords = { ...coords };

          if (e.shiftKey) {
            // 查找包含该点的线段（只考虑两点构成的线段）
            const connectedLines = prev.lines.filter(line => {
              return line.startPointId === draggedPoint.id || line.endPointId === draggedPoint.id;
            });

            // 如果找到连线，检查是否是两点线段
            for (const line of connectedLines) {
              const otherPointId = line.startPointId === draggedPoint.id ? line.endPointId : line.startPointId;
              const otherPoint = prev.points.find(p => p.id === otherPointId);

              if (otherPoint) {
                // 检查这条线段上是否有其他非端点的点（滑动点或交点）
                const pointsOnLine = prev.points.filter(p => {
                  if (p.id === line.startPointId || p.id === line.endPointId) return false;
                  if (p.constrainedToLine &&
                    p.constrainedToLine.startPointId === line.startPointId &&
                    p.constrainedToLine.endPointId === line.endPointId) {
                    return true;
                  }
                  if (p.isIntersection) {
                    const intersectLines = p.intersectionLines || [];
                    if (intersectLines.includes(line.id)) {
                      return true;
                    }
                  }
                  return false;
                });

                // 只有两点构成的线段才应用约束
                if (pointsOnLine.length === 0) {
                  // 计算水平和垂直距离
                  const dx = Math.abs(coords.x - otherPoint.x);
                  const dy = Math.abs(coords.y - otherPoint.y);

                  // 判断应该锁定到水平还是垂直
                  if (dx > dy) {
                    // 水平移动
                    finalCoords.y = otherPoint.y;
                  } else {
                    // 垂直移动
                    finalCoords.x = otherPoint.x;
                  }
                  break; // 只约束第一条符合条件的线段
                }
              }
            }
          }

          // 应用拖动约束
          const constrainedCoords = applyDragConstraints(
            draggedPoint,
            finalCoords,
            prev.dragConstraints || [],
            prev.lines,
            prev.points
          );

          // 首先更新被拖动的点（使用约束后的坐标）
          let updatedPoints = prev.points.map(p =>
            p.id === draggedPoint.id ? { ...p, x: constrainedCoords.x, y: constrainedCoords.y } : p
          );

          // 使用工具函数更新所有依赖于这个点的滑动点
          updatedPoints = updateSlidingPoints(updatedPoints, draggedPoint.id);

          // 更新所有定点的位置（基于固定端点的偏移量）
          updatedPoints = updateFixedPoints(updatedPoints, draggedPoint.id);

          // 更新所有相关的垂足点
          const finalPoints = updatePerpendicularFootPoints(updatedPoints, prev.perpendiculars, draggedPoint.id);

          // 更新所有交点位置（确保交点标签跟随移动）
          const pointsWithUpdatedIntersections = updateIntersectionPoints(
            finalPoints,
            prev.lines,
            prev.parallels || [],
            prev.rays || []
          );

          // 更新所有面积标签的位置
          const updatedLabels = prev.labels.map(label => {
            if (label.isAreaLabel) {
              // 找到关联的常量
              const constant = prev.constants.find(c => c.id === label.linkedConstantId);
              if (constant && constant.pointIds) {
                // 重新计算多边形中心（使用所有点，包括不可拖动的点和间接受影响的点）
                const allPoints = constant.pointIds.map(id =>
                  pointsWithUpdatedIntersections.find(p => p.id === id)
                ).filter(Boolean);

                if (allPoints.length > 0) {
                  let sumX = 0, sumY = 0;
                  allPoints.forEach(p => {
                    sumX += p.x;
                    sumY += p.y;
                  });
                  return {
                    ...label,
                    x: sumX / allPoints.length,
                    y: sumY / allPoints.length
                  };
                }
              }
            }
            return label;
          });

          return {
            ...prev,
            points: pointsWithUpdatedIntersections,
            labels: updatedLabels
          };
        });
        setSelectedItem(prev => ({ ...prev, x: coords.x, y: coords.y }));
      }
    }
  };

  // 鼠标释放
  const handleMouseUp = () => {
    setDragging(null);
  };

  // 删除选中元素
  const handleDelete = () => {
    if (!selectedItem) return;

    if (geometryData.points.find(p => p.id === selectedItem.id)) {
      // 删除点及相关连线、垂线、平行线、射线
      setGeometryData(prev => {
        // 找到所有以此点为起点的垂线
        const perpsToDelete = (prev.perpendiculars || []).filter(p => p.fromPointId === selectedItem.id);
        const footPointIdsToDelete = perpsToDelete.map(p => p.footPointId).filter(Boolean);

        return {
          ...prev,
          points: prev.points.filter(p =>
            p.id !== selectedItem.id && !footPointIdsToDelete.includes(p.id)
          ),
          lines: prev.lines.filter(l =>
            l.startPointId !== selectedItem.id && l.endPointId !== selectedItem.id
          ),
          perpendiculars: (prev.perpendiculars || []).filter(p => p.fromPointId !== selectedItem.id),
          parallels: (prev.parallels || []).filter(p => p.fromPointId !== selectedItem.id),
          rays: (prev.rays || []).filter(r =>
            r.startPointId !== selectedItem.id && r.endPointId !== selectedItem.id
          )
        };
      });
    } else if (geometryData.labels.find(l => l.id === selectedItem.id)) {
      // 删除标签
      setGeometryData(prev => ({
        ...prev,
        labels: prev.labels.filter(l => l.id !== selectedItem.id)
      }));
    } else if (geometryData.lines.find(l => l.id === selectedItem.id)) {
      // 删除线条及相关垂线和垂足点
      setGeometryData(prev => {
        const perpsToDelete = (prev.perpendiculars || []).filter(p =>
          p.toLineStartId === selectedItem.startPointId && p.toLineEndId === selectedItem.endPointId ||
          p.toLineStartId === selectedItem.endPointId && p.toLineEndId === selectedItem.startPointId
        );
        const footPointIdsToDelete = perpsToDelete.map(p => p.footPointId).filter(Boolean);

        return {
          ...prev,
          lines: prev.lines.filter(l => l.id !== selectedItem.id),
          perpendiculars: (prev.perpendiculars || []).filter(p =>
            !(p.toLineStartId === selectedItem.startPointId && p.toLineEndId === selectedItem.endPointId) &&
            !(p.toLineStartId === selectedItem.endPointId && p.toLineEndId === selectedItem.startPointId)
          ),
          points: prev.points.filter(p => !footPointIdsToDelete.includes(p.id))
        };
      });
    } else if ((geometryData.perpendiculars || []).find(p => p.id === selectedItem.id)) {
      // 删除垂线及其垂足点
      const perp = geometryData.perpendiculars.find(p => p.id === selectedItem.id);
      setGeometryData(prev => ({
        ...prev,
        perpendiculars: (prev.perpendiculars || []).filter(p => p.id !== selectedItem.id),
        points: prev.points.filter(p => p.id !== perp.footPointId)
      }));
    }

    setSelectedItem(null);
  };

  // 删除约束
  const handleDeleteConstraint = (constraintType, constraintId) => {
    if (constraintType === 'perpendicular') {
      const perp = geometryData.perpendiculars.find(p => p.id === constraintId);
      setGeometryData(prev => ({
        ...prev,
        perpendiculars: (prev.perpendiculars || []).filter(p => p.id !== constraintId),
        points: prev.points.filter(p => p.id !== perp?.footPointId)
      }));
      toast.success('约束已删除');
    }
  };

  // 获取选中线段的相关约束
  const getLineConstraints = (lineId) => {
    if (!lineId) return { perpendiculars: [] };

    const line = geometryData.lines.find(l => l.id === lineId);
    if (!line) return { perpendiculars: [] };

    // 找到垂直于这条线段的垂线
    const perpendiculars = (geometryData.perpendiculars || []).filter(p => {
      return (p.toLineStartId === line.startPointId && p.toLineEndId === line.endPointId) ||
        (p.toLineStartId === line.endPointId && p.toLineEndId === line.startPointId);
    });

    return { perpendiculars };
  };


  // 打开设置对话框
  const handleOpenSettings = async () => {
    const result = await showDialog({
      title: '工作区设置',
      message: '配置常用颜色和默认字号',
      fields: [
        {
          name: 'commonColors',
          label: '常用颜色',
          type: 'colorGroup',
          colors: [
            {
              name: 'commonColor1',
              label: '常用色1',
              defaultValue: workspaceDefaults.commonColors?.[0] || '#FF0000'
            },
            {
              name: 'commonColor2',
              label: '常用色2',
              defaultValue: workspaceDefaults.commonColors?.[1] || '#00FF00'
            },
            {
              name: 'commonColor3',
              label: '常用色3',
              defaultValue: workspaceDefaults.commonColors?.[2] || '#0000FF'
            }
          ]
        },
        {
          name: 'lineLabelSize',
          label: '线段标签字号',
          type: 'number',
          defaultValue: workspaceDefaults.defaultFontSizes?.lineLabel || 16,
          min: 8,
          max: 72,
          required: true
        },
        {
          name: 'areaLabelSize',
          label: '面积标签字号',
          type: 'number',
          defaultValue: workspaceDefaults.defaultFontSizes?.areaLabel || 18,
          min: 8,
          max: 72,
          required: true
        },
        {
          name: 'pointLabelSize',
          label: '点标签字号',
          type: 'number',
          defaultValue: workspaceDefaults.defaultFontSizes?.pointLabel || 16,
          min: 8,
          max: 72,
          required: true
        }
      ],
      confirmText: '保存',
      cancelText: '取消'
    });

    if (!result) return;

    try {
      const newSettings = {
        commonColors: [
          result.commonColor1,
          result.commonColor2,
          result.commonColor3
        ],
        defaultFontSizes: {
          lineLabel: parseInt(result.lineLabelSize),
          areaLabel: parseInt(result.areaLabelSize),
          pointLabel: parseInt(result.pointLabelSize)
        }
      };

      await settingsAPI.updateWorkspaceDefaults(newSettings);
      setWorkspaceDefaults(newSettings);
      toast.success('设置已保存');
    } catch (err) {
      toast.error('保存设置失败: ' + err.message);
    }
  };

  // 清空画布
  const handleClear = async () => {
    const confirmed = await showConfirm({
      message: '确定要清空画布吗？所有顶点、连线和标签都将被删除。',
      confirmText: '清空',
      cancelText: '取消'
    });

    if (confirmed) {
      setGeometryData(prev => ({
        ...prev,
        points: [],
        lines: [],
        labels: []
      }));
      setSelectedItem(null);
      toast.success('画布已清空');
    }
  };

  // 保存模型
  const handleSave = async (silent = false) => {
    if (!formData.chapter_id || !formData.title) {
      if (!silent) toast.warning('请填写章节和标题');
      return;
    }

    // 验证特殊模型必须选择模板
    if (formData.is_special && !formData.template_path) {
      if (!silent) toast.warning('特殊模型必须选择模板');
      return;
    }

    setSaving(true);
    try {
      let canvasDataToSave = geometryData;

      // 特殊模型：使用模板的默认数据
      if (formData.is_special) {
        const selectedTemplate = getAvailableTemplates().find(t => t.value === formData.template_path);
        if (selectedTemplate && selectedTemplate.defaultData) {
          canvasDataToSave = selectedTemplate.defaultData;
        } else {
          canvasDataToSave = {};
        }
      }

      const payload = {
        chapter_id: formData.chapter_id,
        title: formData.title,
        order_num: formData.order_num,
        canvas_data: canvasDataToSave, // 使用处理后的数据
        is_special: formData.is_special,
        template_path: formData.is_special ? formData.template_path : null,
        is_hidden: false
      };

      if (id) {
        // 如果当前正在编辑某个状态，只更新该状态
        if (currentStateId) {
          await stateAPI.updateState(currentStateId, {
            canvas_data: geometryData
          });
          // 更新本地状态列表
          setModelStates(modelStates.map(s =>
            s.id === currentStateId ? { ...s, canvas_data: geometryData } : s
          ));
          if (!silent) toast.success(`状态已保存！`);
        } else {
          // 否则更新模型（母版）
          await modelAPI.update(id, payload);
          setMasterData(geometryData);
          if (!silent) toast.success('模型已保存！');
        }
      } else {
        await modelAPI.create(payload);
        if (!silent) toast.success('模型创建成功！');
        navigate('/admin');
      }
    } catch (err) {
      if (!silent) toast.error('保存失败: ' + err.message);
    } finally {
      setSaving(false);
    }
  };

  // ============ 常量编辑函数 ============

  // 编辑常量名称
  const handleEditConstant = async (constant) => {
    const result = await showDialog({
      title: '编辑常量名称',
      message: '请输入新的常量名称',
      fields: [
        {
          name: 'name',
          label: '常量名称',
          type: 'text',
          placeholder: constant.type === 'angle' ? '例如：∠ABC' :
                       constant.type === 'length' ? '例如：AB' :
                       '例如：S△ABC 或 SABCD',
          defaultValue: constant.name,
          required: true
        }
      ],
      confirmText: '确认',
      cancelText: '取消'
    });

    if (!result || !result.name || result.name === constant.name) return;

    // 检查名称是否重复
    const isDuplicate = geometryData.constants.some(c => c.id !== constant.id && c.name === result.name);
    if (isDuplicate) {
      toast.error('常量名称已存在');
      return;
    }

    // 更新常量名称
    setGeometryData(prev => ({
      ...prev,
      constants: prev.constants.map(c =>
        c.id === constant.id ? { ...c, name: result.name } : c
      )
    }));

    toast.success('常量名称已更新');
  };

  // ============ 状态管理函数 ============

  // 添加新状态
  const handleAddState = async () => {
    if (!id) {
      toast.warning('请先保存模型');
      return;
    }

    // 构建状态选项列表
    const stateOptions = [
      { value: 'master', label: '母版' },
      ...modelStates.map(state => ({
        value: state.id.toString(),
        label: state.button_label
      }))
    ];

    const result = await showDialog({
      title: '添加新状态',
      message: '请选择基础状态并输入按钮标签',
      fields: [
        {
          name: 'baseState',
          label: '基础状态',
          type: 'select',
          options: stateOptions,
          defaultValue: currentStateId ? currentStateId.toString() : 'master',
          required: true
        },
        {
          name: 'buttonLabel',
          label: '按钮标签',
          type: 'text',
          placeholder: '例如：状态1',
          required: true
        }
      ],
      confirmText: '确认',
      cancelText: '取消'
    });

    if (!result || !result.baseState || !result.buttonLabel) return;

    try {
      // 根据选择的基础状态获取数据
      let baseData;
      if (result.baseState === 'master') {
        baseData = masterData || geometryData;
      } else {
        const baseState = modelStates.find(s => s.id.toString() === result.baseState);
        baseData = baseState ? baseState.canvas_data : (masterData || geometryData);
      }

      // 创建新状态
      const newState = await stateAPI.createState(id, {
        button_label: result.buttonLabel,
        canvas_data: baseData
      });

      setModelStates([...modelStates, newState]);
      toast.success('状态添加成功！');
    } catch (err) {
      toast.error('添加状态失败: ' + err.message);
    }
  };

  // 切换到某个状态
  const handleSwitchState = (stateId) => {
    if (stateId === null) {
      // 切换到母版
      setCurrentStateId(null);
      setGeometryData(masterData || geometryData);
    } else {
      // 切换到指定状态
      const state = modelStates.find(s => s.id === stateId);
      if (state) {
        setCurrentStateId(stateId);
        setGeometryData(state.canvas_data);
      }
    }
    setSelectedItem(null);
  };

  // 编辑状态标签
  const handleEditStateLabel = async (stateId) => {
    const state = modelStates.find(s => s.id === stateId);
    if (!state) return;

    const result = await showDialog({
      title: '编辑标签',
      message: '请输入新的按钮标签',
      fields: [
        {
          name: 'newLabel',
          label: '按钮标签',
          type: 'text',
          placeholder: '例如：状态1',
          defaultValue: state.button_label,
          required: true
        }
      ],
      confirmText: '确认',
      cancelText: '取消'
    });

    const newLabel = result?.newLabel;
    if (!newLabel || newLabel === state.button_label) return;

    try {
      await stateAPI.updateState(stateId, {
        button_label: newLabel
      });

      setModelStates(modelStates.map(s =>
        s.id === stateId ? { ...s, button_label: newLabel } : s
      ));

      toast.success('标签已更新');
    } catch (err) {
      toast.error('更新标签失败: ' + err.message);
    }
  };

  // 删除状态
  const handleDeleteState = async (stateId) => {
    const confirmed = await showConfirm({
      message: '确定要删除这个状态吗？此操作不可恢复。',
      confirmText: '删除',
      cancelText: '取消'
    });

    if (!confirmed) return;

    try {
      await stateAPI.deleteState(stateId);
      setModelStates(modelStates.filter(s => s.id !== stateId));

      // 如果删除的是当前状态，切换回母版
      if (currentStateId === stateId) {
        handleSwitchState(null);
      }

      toast.success('状态已删除');
    } catch (err) {
      toast.error('删除状态失败: ' + err.message);
    }
  };

  // 键盘事件
  useEffect(() => {
    const handleKeyDown = (e) => {
      if (e.key === 'Delete' && selectedItem) {
        handleDelete();
      } else if (e.key === 'Escape') {
        setSelectedItem(null);
        setCurrentTool('select');
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedItem]);

  return (
    <>
      <div className="geometry-workspace">
        <div className="workspace-header">
          <button onClick={() => navigate(-1)} className="back-btn">← 返回</button>
          <h1>{id ? '编辑几何模型' : '创建几何模型'}</h1>
          <div className="header-form">
            <div className="form-field-inline">
              <label>所属章节</label>
              <select
                value={formData.chapter_id}
                onChange={(e) => setFormData({ ...formData, chapter_id: e.target.value })}
                required
              >
                <option value="">选择章节</option>
                {chapters.map(chapter => (
                  <option key={chapter.id} value={chapter.id}>
                    {chapter.title}
                  </option>
                ))}
              </select>
            </div>
            <div className="form-field-inline">
              <label>模型标题</label>
              <input
                type="text"
                value={formData.title}
                onChange={(e) => setFormData({ ...formData, title: e.target.value })}
                placeholder="输入模型标题"
                required
              />
            </div>
            {isSpecialMode && (
              <div className="form-field-inline">
                <label>模板</label>
                <select
                  value={formData.template_path}
                  onChange={(e) => setFormData({ ...formData, template_path: e.target.value })}
                  required
                >
                  <option value="">选择模板</option>
                  {getAvailableTemplates().map(template => (
                    <option key={template.value} value={template.value}>
                      {template.label}
                    </option>
                  ))}
                </select>
              </div>
            )}
          </div>
          <div style={{ display: 'flex', gap: '0.5rem' }}>
            <button onClick={handleOpenSettings} className="settings-btn" title="工作区设置">
              <Settings size={18} />
            </button>
            <button onClick={handleSave} className="save-btn" disabled={saving}>
              {saving ? '保存中...' : <><Save size={18} /> 保存</>}
            </button>
          </div>
        </div>

        <div className={`workspace-content ${!id ? 'no-states' : ''}`}>
          {/* 特殊模型提示 */}
          {isSpecialMode && (
            <div className="special-model-notice">
              <div className="notice-icon">
                <Sparkles size={24} />
              </div>
              <div className="notice-content">
                <strong>特殊模型创建模式</strong>
                <p>特殊模型使用预定义模板实现高级交互功能。请选择模板并填写标题后保存。</p>
              </div>
            </div>
          )}

          {/* 左侧工具栏 - 仅在普通模式显示 */}
          {!isSpecialMode && (
            <div className="toolbar">
              <div className="tool-group">
                <button
                  className={`tool-btn ${currentTool === 'select' ? 'active' : ''}`}
                  onClick={() => {
                    setCurrentTool('select');
                    if (constantMode) {
                      setConstantMode(null);
                      setSelectedPointsForConstant([]);
                    }
                    if (pointOnLineMode) {
                      setPointOnLineMode(null);
                    }
                  }}
                  title="选择/移动"
                >
                  <MousePointer2 className="tool-icon" size={20} />
                </button>
                <button
                  className={`tool-btn ${currentTool === 'point' ? 'active' : ''}`}
                  onClick={() => {
                    setCurrentTool('point');
                    if (constantMode) {
                      setConstantMode(null);
                      setSelectedPointsForConstant([]);
                    }
                    if (pointOnLineMode) {
                      setPointOnLineMode(null);
                    }
                  }}
                  title="添加顶点"
                >
                  <Circle className="tool-icon" size={20} />
                </button>
                <button
                  className={`tool-btn ${currentTool === 'line' ? 'active' : ''}`}
                  onClick={() => {
                    setCurrentTool('line');
                    setSelectedItem(null); // 清除选中状态
                    if (constantMode) {
                      setConstantMode(null);
                      setSelectedPointsForConstant([]);
                    }
                    if (pointOnLineMode) {
                      setPointOnLineMode(null);
                    }
                  }}
                  title="连线"
                >
                  <Minus className="tool-icon" size={20} />
                </button>
              </div>

              <div className="tool-group">
                {!perpendicularMode ? (
                  <button
                    className={`tool-btn ${currentTool === 'perpendicular' ? 'active' : ''}`}
                    onClick={() => {
                      setPerpendicularMode({ fromPoint: null, toLine: null });
                      setCurrentTool('perpendicular');
                      if (constantMode) {
                        setConstantMode(null);
                        setSelectedPointsForConstant([]);
                      }
                      if (pointOnLineMode) {
                        setPointOnLineMode(null);
                      }
                      if (parallelMode) {
                        setParallelMode(null);
                      }
                    }}
                    title="添加垂线"
                  >
                    <Milestone size={20} />
                  </button>
                ) : (
                  <div className="constant-mode-panel">
                    <div className="constant-mode-info">
                      <strong>添加垂线</strong>
                      <p className="hint-text">
                        {!perpendicularMode.fromPoint
                          ? '1. 点击起始点'
                          : '2. 点击目标线段'}
                      </p>
                    </div>
                    <div className="constant-mode-actions">
                      <button
                        className="action-btn danger"
                        onClick={() => {
                          setPerpendicularMode(null);
                          setCurrentTool('select');
                        }}
                      >
                        <X size={16} />
                        <span>取消</span>
                      </button>
                    </div>
                  </div>
                )}

                {!parallelMode ? (
                  <button
                    className={`tool-btn ${currentTool === 'parallel' ? 'active' : ''}`}
                    onClick={() => {
                      setParallelMode({ fromPoint: null, toLine: null });
                      setCurrentTool('parallel');
                      if (constantMode) {
                        setConstantMode(null);
                        setSelectedPointsForConstant([]);
                      }
                      if (pointOnLineMode) {
                        setPointOnLineMode(null);
                      }
                      if (perpendicularMode) {
                        setPerpendicularMode(null);
                      }
                    }}
                    title="添加平行线"
                  >
                    <Milestone size={20} style={{ transform: 'rotate(90deg)' }} />
                  </button>
                ) : (
                  <div className="constant-mode-panel">
                    <div className="constant-mode-info">
                      <strong>添加平行线</strong>
                      <p className="hint-text">
                        点击起始点，然后输入目标线段
                      </p>
                    </div>
                    <div className="constant-mode-actions">
                      <button
                        className="action-btn danger"
                        onClick={() => {
                          setParallelMode(null);
                          setCurrentTool('select');
                        }}
                      >
                        <X size={16} />
                        <span>取消</span>
                      </button>
                    </div>
                  </div>
                )}

                <button
                  className={`tool-btn ${currentTool === 'ray' ? 'active' : ''}`}
                  onClick={() => {
                    setCurrentTool('ray');
                    setSelectedItem(null);
                    if (constantMode) {
                      setConstantMode(null);
                      setSelectedPointsForConstant([]);
                    }
                    if (pointOnLineMode) {
                      setPointOnLineMode(null);
                    }
                    if (perpendicularMode) {
                      setPerpendicularMode(null);
                    }
                    if (parallelMode) {
                      setParallelMode(null);
                    }
                  }}
                  title="添加射线"
                >
                  <GitCommit size={20} />
                </button>
              </div>

              <div className="tool-group">
                <button
                  className="action-btn danger"
                  onClick={handleClear}
                  title="清空画布"
                >
                  <Trash2 size={20} />
                </button>
                <button
                  className="action-btn"
                  onClick={handleDelete}
                  disabled={!selectedItem}
                  title="删除选中"
                >
                  <X size={20} />
                </button>
              </div>

              {!constantMode ? (
                <button
                  className="action-btn add-constant-btn"
                  onClick={() => {
                    setConstantMode({ type: 'angle', name: '', editing: true });
                    setCurrentTool('select');
                  }}
                  title="添加常量"
                >
                  <Hash size={20} />
                </button>
              ) : constantMode.editing ? (
                <div className="constant-config-panel">
                  <div className="constant-config-form">
                    <div className="constant-config-row">
                      <label>类型:</label>
                      <div className="constant-type-buttons">
                        <button
                          className={`type-btn ${constantMode.type === 'angle' ? 'active' : ''}`}
                          onClick={() => setConstantMode(prev => ({ ...prev, type: 'angle', name: '' }))}
                        >
                          角度
                        </button>
                        <button
                          className={`type-btn ${constantMode.type === 'length' ? 'active' : ''}`}
                          onClick={() => setConstantMode(prev => ({ ...prev, type: 'length', name: '' }))}
                        >
                          长度
                        </button>
                        <button
                          className={`type-btn ${constantMode.type === 'area' ? 'active' : ''}`}
                          onClick={() => setConstantMode(prev => ({ ...prev, type: 'area', name: '', areaMode: 'points' }))}
                        >
                          面积
                        </button>
                      </div>
                    </div>

                    {/* 面积模式选择 */}
                    {constantMode.type === 'area' && (
                      <div className="constant-config-row">
                        <label>面积模式:</label>
                        <div className="constant-type-buttons">
                          <button
                            className={`type-btn ${constantMode.areaMode === 'points' ? 'active' : ''}`}
                            onClick={() => setConstantMode(prev => ({ ...prev, areaMode: 'points' }))}
                          >
                            基于点
                          </button>
                          <button
                            className={`type-btn ${constantMode.areaMode === 'compose' ? 'active' : ''}`}
                            onClick={() => setConstantMode(prev => ({ ...prev, areaMode: 'compose' }))}
                          >
                            组合面积
                          </button>
                        </div>
                      </div>
                    )}

                    <div className="constant-config-row">
                      <label>名称:</label>
                      <input
                        type="text"
                        className="constant-name-input"
                        value={constantMode.name}
                        onChange={(e) => setConstantMode(prev => ({ ...prev, name: e.target.value }))}
                        placeholder={
                          constantMode.type === 'angle' ? '例如：∠ABC' :
                            constantMode.type === 'length' ? '例如：AB' :
                              constantMode.areaMode === 'compose' ? '例如：S总 或 S阴影' :
                                '例如：S△ABC 或 SABCD'
                        }
                      />
                    </div>

                    <div className="constant-config-row" style={{ alignItems: 'center' }}>
                      <label style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '0.5rem', fontSize: '0.875rem' }}>
                        <input
                          type="checkbox"
                          checked={constantMode.enableSymbolConversion !== false}
                          onChange={(e) => setConstantMode(prev => ({ ...prev, enableSymbolConversion: e.target.checked }))}
                          style={{ width: 'auto', margin: 0 }}
                        />
                        应用符号转换（三角形→△）
                      </label>
                    </div>
                  </div>

                  <div className="constant-config-actions">
                    <button
                      className="action-btn"
                      onClick={() => {
                        if (!constantMode.name.trim()) {
                          toast.warning('请输入常量名称');
                          return;
                        }
                        setConstantMode(prev => ({ ...prev, editing: false }));
                        setCurrentTool('constant');
                        setSelectedPointsForConstant([]);
                        setSelectedAreasForConstant([]);
                      }}
                    >
                      <Check size={16} />
                      <span>{constantMode.type === 'area' && constantMode.areaMode === 'compose' ? '开始选择面积' : '开始选点'}</span>
                    </button>
                    <button
                      className="action-btn danger"
                      onClick={() => {
                        setConstantMode(null);
                        setCurrentTool('select');
                      }}
                    >
                      <X size={16} />
                      <span>取消</span>
                    </button>
                  </div>
                </div>
              ) : (
                <div className="constant-mode-panel">
                  <div className="constant-mode-info">
                    <strong>{constantMode.name}</strong>
                    <p className="hint-text">
                      {constantMode.type === 'angle' && `需要3个点（第2个为顶点），已选 ${selectedPointsForConstant.length}/3`}
                      {constantMode.type === 'length' && `需要2个点，已选 ${selectedPointsForConstant.length}/2`}
                      {constantMode.type === 'area' && constantMode.areaMode === 'points' && `至少3个点，已选 ${selectedPointsForConstant.length}`}
                      {constantMode.type === 'area' && constantMode.areaMode === 'compose' && `至少选择1个面积，已选 ${selectedAreasForConstant.length}`}
                    </p>
                    <p className="selected-points">
                      {constantMode.areaMode === 'compose' ? (
                        selectedAreasForConstant.map(id => {
                          const area = geometryData.constants.find(c => c.id === id);
                          return area?.name || `面积${id}`;
                        }).join(' + ')
                      ) : (
                        selectedPointsForConstant.map(id => {
                          const p = geometryData.points.find(p => p.id === id);
                          return p?.label || `点${id}`;
                        }).join(' → ')
                      )}
                    </p>
                  </div>
                  <div className="constant-mode-actions">
                    <button
                      className="action-btn"
                      onClick={async () => {
                        if (constantMode.type === 'angle' && selectedPointsForConstant.length !== 3) {
                          toast.warning('角度需要选择3个点');
                          return;
                        }

                        if (constantMode.type === 'length' && selectedPointsForConstant.length !== 2) {
                          toast.warning('长度需要选择2个点');
                          return;
                        }

                        if (constantMode.type === 'area' && constantMode.areaMode === 'points' && selectedPointsForConstant.length < 3) {
                          toast.warning('面积至少需要选择3个点');
                          return;
                        }

                        if (constantMode.type === 'area' && constantMode.areaMode === 'compose' && selectedAreasForConstant.length < 1) {
                          toast.warning('至少需要选择1个面积');
                          return;
                        }

                        // 编辑模式：更新现有常量
                        if (constantMode.editingId) {
                          setGeometryData(prev => ({
                            ...prev,
                            constants: prev.constants.map(c =>
                              c.id === constantMode.editingId ? {
                                ...c,
                                pointIds: (constantMode.type === 'area' && constantMode.areaMode === 'compose') ? [] : selectedPointsForConstant,
                                composedOf: constantMode.areaMode === 'compose' ? selectedAreasForConstant : undefined
                              } : c
                            ),
                            // 更新关联的面积标签位置
                            labels: constantMode.type === 'area' && constantMode.areaMode === 'points' ?
                              prev.labels.map(label => {
                                if (label.isAreaLabel && label.linkedConstantId === constantMode.editingId) {
                                  const points = selectedPointsForConstant.map(id =>
                                    prev.points.find(p => p.id === id)
                                  ).filter(Boolean);
                                  if (points.length > 0) {
                                    let sumX = 0, sumY = 0;
                                    points.forEach(p => { sumX += p.x; sumY += p.y; });
                                    return { ...label, x: sumX / points.length, y: sumY / points.length };
                                  }
                                }
                                return label;
                              }) : prev.labels
                          }));
                          toast.success('常量更新成功！');
                        } else {
                          // 新建模式：创建新常量
                          if (constantMode.type === 'area' && constantMode.areaMode === 'points') {
                            const points = selectedPointsForConstant.map(id =>
                              geometryData.points.find(p => p.id === id)
                            );

                            // 计算多边形中心点
                            const getCenter = (pts) => {
                              let sumX = 0, sumY = 0;
                              pts.forEach(p => {
                                sumX += p.x;
                                sumY += p.y;
                              });
                              return { x: sumX / pts.length, y: sumY / pts.length };
                            };

                            const center = getCenter(points);
                            const constantId = Date.now();
                            const newLabel = {
                              id: Date.now() + 1,
                              x: center.x,
                              y: center.y,
                              text: constantMode.name,
                              fontSize: 16,
                              color: '#000000',
                              isAreaLabel: true,
                              linkedConstantId: constantId
                            };
                            setGeometryData(prev => ({
                              ...prev,
                              labels: [...prev.labels, newLabel]
                            }));
                          }

                          const newConstant = {
                            id: Date.now(),
                            type: constantMode.type,
                            name: constantMode.name,
                            pointIds: (constantMode.type === 'area' && constantMode.areaMode === 'compose') ? [] : selectedPointsForConstant,
                            composedOf: constantMode.areaMode === 'compose' ? selectedAreasForConstant : undefined,
                            enableSymbolConversion: constantMode.enableSymbolConversion !== false  // 保存符号转换选项
                          };

                          setGeometryData(prev => ({
                            ...prev,
                            constants: [...(prev.constants || []), newConstant]
                          }));
                        }

                        setSelectedPointsForConstant([]);
                        setSelectedAreasForConstant([]);
                        setConstantMode(null);
                        setCurrentTool('select');
                      }}
                    >
                      <Check size={16} />
                      <span>确认</span>
                    </button>
                    <button
                      className="action-btn danger"
                      onClick={() => {
                        setSelectedPointsForConstant([]);
                        setConstantMode(null);
                        setCurrentTool('select');
                      }}
                    >
                      <X size={16} />
                      <span>取消</span>
                    </button>
                  </div>
                </div>
              )}

              {/* 添加/编辑表达式 */}
              {!expressionMode ? (
                <button
                  className="action-btn add-expression-btn"
                  onClick={() => {
                    if (geometryData.constants.length === 0) {
                      toast.warning('请先添加常量');
                      return;
                    }
                    setExpressionMode({ parts: [], editing: true });
                    setEditingExpressionId(null);
                    setCurrentTool('select');
                  }}
                  title="添加表达式"
                >
                  <Code size={20} />
                </button>
              ) : (
                <div className="expression-mode-panel">
                  <div className="expression-mode-header">
                    <Code size={16} />
                    <span>{editingExpressionId ? '编辑表达式' : '添加表达式'}</span>
                  </div>

                  <div className="expression-mode-content">
                    <div className="expression-mode-preview">
                      {expressionMode.parts.map((part, idx) => {
                        if (part.type === 'constant') {
                          const constant = geometryData.constants.find(c => c.name === part.name);
                          const enableConversion = constant?.enableSymbolConversion !== false;
                          
                          if (constant && constant.type === 'area') {
                            const content = part.name.replace(/^[Ss]+/g, '');
                            const convertedContent = convertToMathSymbols(content, enableConversion);
                            return <span key={idx} className="part-constant">S<sub>{convertedContent}</sub></span>;
                          }
                          const convertedName = convertToMathSymbols(part.name, enableConversion);
                          return <span key={idx} className="part-constant">{convertedName}</span>;
                        } else if (part.type === 'number') {
                          return <span key={idx} className="part-number">{part.value}</span>;
                        } else if (part.type === 'operator') {
                          if (part.value === '/') {
                            return <span key={idx} className="part-operator">/</span>;
                          } else if (part.value === 'div') {
                            return <span key={idx} className="part-operator">÷</span>;
                          } else if (part.value === '*') {
                            return <span key={idx} className="part-operator">×</span>;
                          } else if (part.value === '+') {
                            return <span key={idx} className="part-operator">+</span>;
                          } else if (part.value === '-') {
                            return <span key={idx} className="part-operator">−</span>;
                          } else if (part.value === '=') {
                            return <span key={idx} className="part-operator"> = </span>;
                          } else if (part.value === ':') {
                            return <span key={idx} className="part-operator"> : </span>;
                          } else if (part.value === '^2') {
                            return <span key={idx} className="part-operator">²</span>;
                          }
                        } else if (part.type === 'bracket') {
                          return <span key={idx} className="part-operator">{part.value}</span>;
                        }
                        return null;
                      })}
                      {expressionMode.parts.length === 0 && <span className="placeholder-text">选择常量、数字和运算符构建表达式</span>}
                    </div>

                    <div className="expression-mode-selectors">
                      {/* 常量选择区 */}
                      <div className="expression-selector-group">
                        <label>常量</label>
                        <div className="expression-selector-buttons constant-selector">
                          {geometryData.constants.map(constant => {
                            const enableConversion = constant.enableSymbolConversion !== false;
                            let displayName;
                            
                            if (constant.type === 'area') {
                              const content = constant.name.replace(/^[Ss]+/g, '');
                              const convertedContent = convertToMathSymbols(content, enableConversion);
                              displayName = `S${convertedContent}`;
                            } else {
                              displayName = convertToMathSymbols(constant.name, enableConversion);
                            }
                            
                            return (
                              <button
                                key={constant.id}
                                className="selector-btn"
                                onClick={() => {
                                  setExpressionMode(prev => ({
                                    ...prev,
                                    parts: [...prev.parts, { type: 'constant', name: constant.name }]
                                  }));
                                }}
                              >
                                {displayName}
                              </button>
                            );
                          })}
                        </div>
                      </div>

                      {/* 运算符选择区 */}
                      <div className="expression-selector-group">
                        <label>运算符</label>
                        <div className="expression-selector-buttons operator-selector">
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: '=' }]
                              }));
                            }}
                          >
                            =
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: '+' }]
                              }));
                            }}
                          >
                            +
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: '-' }]
                              }));
                            }}
                          >
                            −
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: '*' }]
                              }));
                            }}
                          >
                            ×
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: '/' }]
                              }));
                            }}
                          >
                            /
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: 'div' }]
                              }));
                            }}
                            title="分式除法"
                          >
                            ÷
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: ':' }]
                              }));
                            }}
                            title="比值"
                          >
                            :
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'operator', value: '^2' }]
                              }));
                            }}
                            title="平方"
                          >
                            x²
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'bracket', value: '(' }]
                              }));
                            }}
                            title="左括号"
                          >
                            (
                          </button>
                          <button
                            className="selector-btn"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: [...prev.parts, { type: 'bracket', value: ')' }]
                              }));
                            }}
                            title="右括号"
                          >
                            )
                          </button>
                          <button
                            className="selector-btn undo"
                            onClick={() => {
                              setExpressionMode(prev => ({
                                ...prev,
                                parts: prev.parts.slice(0, -1)
                              }));
                            }}
                            title="撤销上一步"
                          >
                            ←
                          </button>
                        </div>
                      </div>

                      {/* 数字输入区 */}
                      <div className="expression-selector-group">
                        <label>数字</label>
                        <div className="expression-selector-buttons number-input-selector">
                          <input
                            type="number"
                            step="0.01"
                            placeholder="输入数字后按回车或点击添加"
                            onKeyDown={(e) => {
                              if (e.key === 'Enter' && e.target.value) {
                                const num = parseFloat(e.target.value);
                                if (!isNaN(num)) {
                                  setExpressionMode(prev => ({
                                    ...prev,
                                    parts: [...prev.parts, { type: 'number', value: num }]
                                  }));
                                  e.target.value = '';
                                }
                              }
                            }}
                          />
                          <button
                            className="selector-btn"
                            onClick={(e) => {
                              const input = e.target.closest('.number-input-selector').querySelector('input');
                              const num = parseFloat(input.value);
                              if (!isNaN(num)) {
                                setExpressionMode(prev => ({
                                  ...prev,
                                  parts: [...prev.parts, { type: 'number', value: num }]
                                }));
                                input.value = '';
                              } else {
                                toast.warning('请输入有效数字');
                              }
                            }}
                          >
                            添加
                          </button>
                        </div>
                      </div>
                    </div>

                    <div className="expression-mode-actions">
                      <button
                        className="action-btn"
                        onClick={() => {
                          if (expressionMode.parts.length === 0) {
                            toast.warning('表达式不能为空');
                            return;
                          }

                          const newExpression = {
                            id: editingExpressionId || Date.now(),
                            parts: expressionMode.parts
                          };

                          // 验证表达式是否成立
                          if (!validateExpression(newExpression, getConstantValue)) {
                            toast.error('等式不成立，无法创建表达式');
                            return;
                          }

                          if (editingExpressionId) {
                            setGeometryData(prev => ({
                              ...prev,
                              expressions: prev.expressions.map(e =>
                                e.id === editingExpressionId ? newExpression : e
                              )
                            }));
                            toast.success('表达式已更新');
                          } else {
                            setGeometryData(prev => ({
                              ...prev,
                              expressions: [...(prev.expressions || []), newExpression]
                            }));
                            toast.success('表达式已创建');
                          }

                          setExpressionMode(null);
                          setEditingExpressionId(null);
                        }}
                      >
                        <Check size={16} />
                        <span>确认</span>
                      </button>
                      <button
                        className="action-btn danger"
                        onClick={() => {
                          setExpressionMode(null);
                          setEditingExpressionId(null);
                        }}
                      >
                        <X size={16} />
                        <span>取消</span>
                      </button>
                    </div>
                  </div>
                </div>
              )}

            </div>
          )}

          {/* 中间画布区 - 仅在普通模式显示 */}
          {!isSpecialMode && (
            <div className="canvas-section">
              {/* 监控面板容器 - 左上角浮动 */}
              {((geometryData.constants && geometryData.constants.length > 0) ||
                (geometryData.expressions && geometryData.expressions.length > 0)) && (() => {
                  // 收集所有数值用于误差调整
                  const allValues = [];

                  // 辅助函数：判断表达式是否只包含面积类型的常量
                  const isExpressionOnlyArea = (expression) => {
                    if (!expression.parts || expression.parts.length === 0) return false;
                    for (const part of expression.parts) {
                      if (part.type === 'constant') {
                        const constant = geometryData.constants.find(c => c.name === part.name);
                        if (!constant || constant.type !== 'area') {
                          return false;
                        }
                      }
                    }
                    return true;
                  };

                  // 只收集面积类型的常量值
                  if (geometryData.constants && geometryData.constants.length > 0) {
                    geometryData.constants.forEach(constant => {
                      if (constant.type === 'area') {
                        const rawValue = calculateConstantValue(constant, geometryData.points, geometryData.constants);
                        const num = parseFloat(rawValue);
                        if (!isNaN(num)) {
                          allValues.push(num);
                        }
                      }
                    });
                  }

                  // 只收集只包含面积常量的表达式结果值
                  if (geometryData.expressions && geometryData.expressions.length > 0) {
                    geometryData.expressions.forEach(expression => {
                      if (isExpressionOnlyArea(expression)) {
                        const result = calculateExpressionValue(expression, getConstantValue);
                        const num = parseFloat(result);
                        if (!isNaN(num)) {
                          allValues.push(num);
                        }
                      }
                    });
                  }

                  // 生成值调整映射（误差在1之内的取平均，仅针对面积）
                  const valueMap = groupAndAverageValues(allValues, 1.0);

                  return (
                    <div className="monitors-container">
                      {/* 常量监控面板 */}
                      {geometryData.constants && geometryData.constants.length > 0 && (
                        <div className="constants-monitor">
                          <div className="constants-monitor-header">常量监控</div>
                          <div className="constants-monitor-list">
                            {geometryData.constants.map((constant, index) => {
                              const rawValue = calculateConstantValue(constant, geometryData.points, geometryData.constants);
                              const num = parseFloat(rawValue);

                              // 只对面积类型的常量使用调整后的值（考虑误差）
                              let adjustedValue = rawValue;
                              if (!isNaN(num)) {
                                if (constant.type === 'area') {
                                  adjustedValue = getAdjustedDisplayValue(num, valueMap, 2);
                                } else {
                                  // 非面积类型直接使用原始值
                                  adjustedValue = num.toFixed(2);
                                }
                                // 如果是角度，添加度数符号
                                if (rawValue.includes('°')) {
                                  adjustedValue += '°';
                                }
                              }

                              const displayName = formatConstantName(constant);
                              const isSelectable = constantMode && constantMode.type === 'area' && constantMode.areaMode === 'compose' && constant.type === 'area';
                              const isSelected = isSelectable && selectedAreasForConstant.includes(constant.id);

                              return (
                                <div
                                  key={constant.id}
                                  className={`constant-monitor-item ${isSelectable ? 'selectable' : ''} ${isSelected ? 'selected' : ''}`}
                                  draggable={true}
                                  onDragStart={(e) => {
                                    e.dataTransfer.effectAllowed = 'move';
                                    e.dataTransfer.setData('text/plain', index.toString());
                                    e.currentTarget.style.opacity = '0.5';
                                  }}
                                  onDragEnd={(e) => {
                                    e.currentTarget.style.opacity = '1';
                                  }}
                                  onDragOver={(e) => {
                                    e.preventDefault();
                                    e.dataTransfer.dropEffect = 'move';
                                  }}
                                  onDrop={(e) => {
                                    e.preventDefault();
                                    const dragIndex = parseInt(e.dataTransfer.getData('text/plain'));
                                    const dropIndex = index;

                                    if (dragIndex !== dropIndex) {
                                      setGeometryData(prev => {
                                        const newConstants = [...prev.constants];
                                        const [draggedItem] = newConstants.splice(dragIndex, 1);
                                        newConstants.splice(dropIndex, 0, draggedItem);
                                        return {
                                          ...prev,
                                          constants: newConstants
                                        };
                                      });
                                    }
                                  }}
                                  onClick={() => {
                                    if (isSelectable) {
                                      if (isSelected) {
                                        setSelectedAreasForConstant(prev => prev.filter(id => id !== constant.id));
                                      } else {
                                        setSelectedAreasForConstant(prev => [...prev, constant.id]);
                                      }
                                    }
                                  }}
                                  style={{ cursor: isSelectable ? 'pointer' : 'grab' }}
                                >
                                  <span className="constant-monitor-name">{displayName}</span>
                                  <span className="constant-monitor-value">{adjustedValue}</span>
                                  <div className="constant-monitor-actions">
                                    {/* 面积常量显示填充控制 */}
                                    {constant.type === 'area' && (
                                      <div className="fill-control" style={{ display: 'flex', gap: '4px', marginRight: '8px' }}>
                                        {FILL_COLORS.map((color, idx) => (
                                          <button
                                            key={idx}
                                            className={`fill-color-btn ${constant.fillColor === color.value ? 'active' : ''}`}
                                            style={{
                                              width: '16px',
                                              height: '16px',
                                              borderRadius: '3px',
                                              backgroundColor: color.hex,
                                              border: constant.fillColor === color.value ? '2px solid #000' : '1px solid #ccc',
                                              cursor: 'pointer',
                                              padding: 0
                                            }}
                                            onClick={() => {
                                              setGeometryData(prev => ({
                                                ...prev,
                                                constants: prev.constants.map(c =>
                                                  c.id === constant.id
                                                    ? { ...c, fill: true, fillColor: color.value }
                                                    : c
                                                )
                                              }));
                                            }}
                                            title={`填充${color.name}`}
                                          />
                                        ))}
                                        {/* 色盘选择器 */}
                                        <input
                                          type="color"
                                          id={`color-picker-${constant.id}`}
                                          style={{ display: 'none' }}
                                          value={constant.fillColor ?
                                            (constant.fillColor.startsWith('rgba') ? '#808080' : constant.fillColor) :
                                            '#808080'
                                          }
                                          onChange={(e) => {
                                            const hex = e.target.value;
                                            const rgba = hexToRgba(hex, 0.15);
                                            setGeometryData(prev => ({
                                              ...prev,
                                              constants: prev.constants.map(c =>
                                                c.id === constant.id
                                                  ? { ...c, fill: true, fillColor: rgba }
                                                  : c
                                              )
                                            }));
                                          }}
                                        />
                                        <button
                                          className="fill-color-picker-btn"
                                          style={{
                                            width: '16px',
                                            height: '16px',
                                            borderRadius: '3px',
                                            backgroundColor: '#fff',
                                            border: '1px solid #ccc',
                                            cursor: 'pointer',
                                            padding: 0,
                                            fontSize: '10px',
                                            lineHeight: '14px',
                                            display: 'flex',
                                            alignItems: 'center',
                                            justifyContent: 'center'
                                          }}
                                          onClick={() => {
                                            document.getElementById(`color-picker-${constant.id}`).click();
                                          }}
                                          title="选择自定义颜色"
                                        >
                                          🎨
                                        </button>
                                        <button
                                          className="fill-clear-btn"
                                          style={{
                                            width: '16px',
                                            height: '16px',
                                            borderRadius: '3px',
                                            backgroundColor: '#fff',
                                            border: '1px solid #ccc',
                                            cursor: 'pointer',
                                            padding: 0,
                                            fontSize: '10px',
                                            lineHeight: '14px'
                                          }}
                                          onClick={() => {
                                            setGeometryData(prev => ({
                                              ...prev,
                                              constants: prev.constants.map(c =>
                                                c.id === constant.id
                                                  ? { ...c, fill: false, fillColor: undefined }
                                                  : c
                                              )
                                            }));
                                          }}
                                          title="清除填充"
                                        >
                                          ×
                                        </button>
                                      </div>
                                    )}
                                    
                                    {/* 符号转换选项 */}
                                    <label
                                      style={{
                                        display: 'flex',
                                        alignItems: 'center',
                                        gap: '4px',
                                        fontSize: '11px',
                                        cursor: 'pointer',
                                        marginRight: '8px',
                                        whiteSpace: 'nowrap'
                                      }}
                                      onClick={(e) => e.stopPropagation()}
                                      title='启用后将"三角形"转换为"△"符号'
                                    >
                                      <input
                                        type="checkbox"
                                        checked={constant.enableSymbolConversion !== false}
                                        onChange={(e) => {
                                          e.stopPropagation();
                                          setGeometryData(prev => ({
                                            ...prev,
                                            constants: prev.constants.map(c =>
                                              c.id === constant.id
                                                ? { ...c, enableSymbolConversion: e.target.checked }
                                                : c
                                            )
                                          }));
                                        }}
                                        style={{ width: 'auto', margin: 0, cursor: 'pointer' }}
                                      />
                                      <span style={{ color: '#666' }}>符号</span>
                                    </label>
                                    
                                    <button
                                      className="constant-monitor-edit"
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        handleEditConstant(constant);
                                      }}
                                      title="编辑常量"
                                    >
                                      <Edit2 size={12} />
                                    </button>
                                    <button
                                      className="constant-monitor-copy"
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        navigator.clipboard.writeText(constant.name);
                                      }}
                                      title="复制常量名"
                                    >
                                      <Copy size={12} />
                                    </button>
                                    <button
                                      className="constant-monitor-delete"
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        setGeometryData(prev => ({
                                          ...prev,
                                          constants: prev.constants.filter(c => c.id !== constant.id)
                                        }));
                                      }}
                                      title="删除常量"
                                    >
                                      <X size={12} />
                                    </button>
                                  </div>
                                </div>
                              );
                            })}
                          </div>
                        </div>
                      )}

                      {/* 表达式监控面板 */}
                      {geometryData.expressions && geometryData.expressions.length > 0 && (
                        <div className="expressions-monitor">
                          <div className="expressions-monitor-header">表达式监控</div>
                          <div className="expressions-monitor-list">
                            {geometryData.expressions.map(expression => {
                              const result = calculateExpressionValue(expression, getConstantValue);

                              // 只对只包含面积常量的表达式使用调整后的值（考虑误差）
                              let adjustedResult = result;
                              if (result !== null && result !== undefined) {
                                const num = parseFloat(result);
                                if (!isNaN(num)) {
                                  if (isExpressionOnlyArea(expression)) {
                                    adjustedResult = getAdjustedDisplayValue(num, valueMap, 2);
                                  } else {
                                    // 非面积表达式直接使用原始值
                                    adjustedResult = num.toFixed(2);
                                  }
                                }
                              }

                              return (
                                <div key={expression.id} className="expression-monitor-item">
                                  <div className="expression-monitor-content">
                                    <span className="expression-monitor-formula">
                                      {renderExpressionFormula(expression)}
                                    </span>
                                    {adjustedResult !== null && <span className="expression-monitor-result">{adjustedResult}</span>}
                                  </div>
                                  <div className="expression-monitor-actions">
                                    <button
                                      className="expression-monitor-edit"
                                      onClick={() => {
                                        setEditingExpressionId(expression.id);
                                        setExpressionMode({ parts: [...expression.parts], editing: true });
                                      }}
                                      title="编辑表达式"
                                    >
                                      <Edit2 size={12} />
                                    </button>
                                    <button
                                      className="expression-monitor-delete"
                                      onClick={() => {
                                        setGeometryData(prev => ({
                                          ...prev,
                                          expressions: prev.expressions.filter(e => e.id !== expression.id)
                                        }));
                                      }}
                                      title="删除表达式"
                                    >
                                      <X size={12} />
                                    </button>
                                  </div>
                                </div>
                              );
                            })}
                          </div>
                        </div>
                      )}
                    </div>
                  );
                })()}

              {/* 约束信息面板 - 选中线段时显示 */}
              {selectedItem && geometryData.lines.find(l => l.id === selectedItem.id) && (() => {
                const constraints = getLineConstraints(selectedItem.id);
                const hasConstraints = constraints.perpendiculars.length > 0;

                if (!hasConstraints) return null;

                return (
                  <div className="constraints-panel">
                    <div className="constraints-panel-header">
                      <span>线段约束</span>
                    </div>
                    <div className="constraints-panel-content">
                      {/* 垂线约束 */}
                      {constraints.perpendiculars.length > 0 && (
                        <div className="constraint-group">
                          <div className="constraint-group-title">垂线 ({constraints.perpendiculars.length})</div>
                          {constraints.perpendiculars.map(perp => {
                            const fromPoint = geometryData.points.find(p => p.id === perp.fromPointId);
                            return (
                              <div key={perp.id} className="constraint-item">
                                <span className="constraint-desc">
                                  从点 {fromPoint?.label || perp.fromPointId.slice(-4)} 到此线段
                                </span>
                                <button
                                  className="constraint-delete-btn"
                                  onClick={() => handleDeleteConstraint('perpendicular', perp.id)}
                                  title="删除垂线"
                                >
                                  <X size={14} />
                                </button>
                              </div>
                            );
                          })}
                        </div>
                      )}
                    </div>
                  </div>
                );
              })()}

              <div className="canvas-toolbar">
                <span className="hint">
                  {currentTool === 'select' && '点击选中元素，拖动可移动'}
                  {currentTool === 'point' && '点击画布添加顶点'}
                  {currentTool === 'line' && !selectedItem && '点击第一个顶点作为起点'}
                  {currentTool === 'line' && selectedItem && '点击第二个顶点完成连线（已选中起点）'}
                  {currentTool === 'ray' && !selectedItem && '点击第一个顶点作为射线起点'}
                  {currentTool === 'ray' && selectedItem && '点击第二个顶点确定射线方向（已选中起点）'}
                  {currentTool === 'perpendicular' && perpendicularMode && (
                    <span style={{ color: '#8B5CF6', fontWeight: 'bold' }}>
                      {!perpendicularMode.fromPoint
                        ? '1. 点击选择起始点（垂线从这个点开始）'
                        : `2. 点击目标线段（已选择起点：${perpendicularMode.fromPoint.label || '点' + perpendicularMode.fromPoint.id}）`}
                    </span>
                  )}
                  {currentTool === 'pointOnLine' && pointOnLineMode && (
                    <span style={{
                      color: pointOnLineMode.type === 'fixed' ? '#8E8E93' :
                          pointOnLineMode.type === 'divide' ? '#66B3FF' : '#007AFF',
                      fontWeight: 'bold'
                    }}>
                      {pointOnLineMode.type === 'fixed'
                          ? '点击线段添加定点（固定位置，不可拖动）'
                          : pointOnLineMode.type === 'divide'
                            ? '等分点添加模式（请在右侧面板选择线段并输入等分数量）'
                            : '点击线段添加滑动点，该点可沿线段移动'}
                    </span>
                  )}
                  {currentTool === 'constant' && constantMode && (
                    <span style={{ color: '#FF9500', fontWeight: 'bold' }}>
                      点击画布上的点进行选择（橙色圆圈），完成后点击左侧"确认"按钮
                    </span>
                  )}
                </span>
                {currentTool === 'pointOnLine' && pointOnLineMode && (
                  <button
                    onClick={() => {
                      setPointOnLineMode(null);
                      setCurrentTool('select');
                      toast.info('已退出编辑模式');
                    }}
                    style={{
                      padding: '0.375rem 0.75rem',
                      fontSize: '0.75rem',
                      background: '#ff3b30',
                      color: 'white',
                      border: 'none',
                      borderRadius: '6px',
                      cursor: 'pointer',
                      fontWeight: 500,
                      display: 'flex',
                      alignItems: 'center',
                      gap: '0.25rem'
                    }}
                  >
                    <X size={14} />
                    退出
                  </button>
                )}
              </div>
              <div className="canvas-wrapper">
                <canvas
                  ref={canvasRef}
                  width={800}
                  height={500}
                  onMouseDown={handleMouseDown}
                  onMouseMove={handleMouseMove}
                  onMouseUp={handleMouseUp}
                  onMouseLeave={handleMouseUp}
                />
              </div>
            </div>
          )}

          {/* 状态管理面板 - 仅在编辑模式和普通模式显示 */}
          {id && !isSpecialMode && (
            <div className="states-panel">
              <div className="states-header">
                <h3>状态管理</h3>
                <button
                  className="add-state-btn"
                  onClick={handleAddState}
                  title="添加新状态"
                >
                  <Plus size={16} />
                  添加状态
                </button>
              </div>

              <div className="states-list">
                {/* 母版按钮 */}
                <div
                  className={`state-item ${currentStateId === null ? 'active' : ''}`}
                  onClick={() => handleSwitchState(null)}
                >
                  <div className="state-info">
                    <Sparkles size={16} />
                    <span className="state-label">母版</span>
                  </div>
                  {/* 占位元素，保持高度一致 */}
                  <div className="state-actions" style={{ opacity: 0, pointerEvents: 'none' }}>
                    <button className="edit-state-btn" style={{ visibility: 'hidden' }}>
                      <Edit2 size={14} />
                    </button>
                    <button className="delete-state-btn" style={{ visibility: 'hidden' }}>
                      <Trash2 size={14} />
                    </button>
                  </div>
                </div>

                {/* 其他状态按钮 */}
                {modelStates.map((state, index) => (
                  <div
                    key={state.id}
                    className={`state-item ${currentStateId === state.id ? 'active' : ''}`}
                    draggable={true}
                    onDragStart={(e) => {
                      e.dataTransfer.effectAllowed = 'move';
                      e.dataTransfer.setData('text/plain', index.toString());
                      e.currentTarget.classList.add('dragging');
                    }}
                    onDragEnd={(e) => {
                      e.currentTarget.classList.remove('dragging');
                    }}
                    onDragOver={(e) => {
                      e.preventDefault();
                      e.dataTransfer.dropEffect = 'move';
                    }}
                    onDrop={async (e) => {
                      e.preventDefault();
                      const dragIndex = parseInt(e.dataTransfer.getData('text/plain'));
                      const dropIndex = index;

                      if (dragIndex !== dropIndex) {
                        // 立即更新本地状态
                        setModelStates(prev => {
                          const newStates = [...prev];
                          const [draggedItem] = newStates.splice(dragIndex, 1);
                          newStates.splice(dropIndex, 0, draggedItem);

                          // 异步保存到后端
                          if (id) {
                            const statesWithOrder = newStates.map((s, idx) => ({
                              id: s.id,
                              order_num: idx + 1
                            }));

                            stateAPI.reorderStates(id, statesWithOrder)
                              .catch(err => {
                                toast.error('保存顺序失败: ' + err.message);
                              });
                          }

                          return newStates;
                        });
                      }
                    }}
                  >
                    <div
                      className="state-info"
                      onClick={() => handleSwitchState(state.id)}
                    >
                      <GripVertical size={16} className="drag-handle" />
                      <span className="state-label">{state.button_label}</span>
                    </div>
                    <div className="state-actions">
                      <button
                        className="edit-state-btn"
                        onClick={(e) => {
                          e.stopPropagation();
                          handleEditStateLabel(state.id);
                        }}
                        title="编辑标签"
                      >
                        <Edit2 size={14} />
                      </button>
                      <button
                        className="delete-state-btn"
                        onClick={(e) => {
                          e.stopPropagation();
                          handleDeleteState(state.id);
                        }}
                        title="删除状态"
                      >
                        <Trash2 size={14} />
                      </button>
                    </div>
                  </div>
                ))}
              </div>

              {/* 当前状态提示 */}
              <div className="current-state-info">
                {currentStateId === null ? (
                  <p>当前编辑: <strong>母版</strong></p>
                ) : (
                  <p>当前编辑: <strong>{modelStates.find(s => s.id === currentStateId)?.button_label}</strong></p>
                )}
              </div>

              {/* 选中元素属性 */}
              {selectedItem && (
                <>
                  <h3 style={{ margin: '1rem 0.875rem 0.75rem', fontSize: '0.6875rem', fontWeight: 600, color: '#86868b', textTransform: 'uppercase', letterSpacing: '0.05em' }}>选中元素</h3>
                  {(selectedItem.type === 'point' || selectedItem.type === 'point-label') && (
                    <div className="selected-info" style={{ margin: '0 0.875rem' }}>
                      <div className="form-group">
                        <label>标签</label>
                        <input
                          type="text"
                          value={selectedItem.label || ''}
                          onChange={(e) => {
                            const newLabel = e.target.value;
                            setGeometryData(prev => ({
                              ...prev,
                              points: prev.points.map(p =>
                                p.id === selectedItem.id ? { ...p, label: newLabel } : p
                              )
                            }));
                            setSelectedItem(prev => ({ ...prev, label: newLabel }));
                          }}
                          placeholder="如: A, B, C"
                        />
                      </div>
                      {selectedItem.label && (
                        <>
                          <div className="form-group">
                            <label>标签字号</label>
                            <input
                              type="number"
                              value={selectedItem.labelFontSize || 20}
                              onChange={(e) => {
                                const newSize = parseInt(e.target.value);
                                setGeometryData(prev => ({
                                  ...prev,
                                  points: prev.points.map(p =>
                                    p.id === selectedItem.id ? { ...p, labelFontSize: newSize } : p
                                  )
                                }));
                                setSelectedItem(prev => ({ ...prev, labelFontSize: newSize }));
                              }}
                              min="8"
                              max="48"
                            />
                          </div>
                        </>
                      )}
                      <div className="form-group" style={{ display: 'flex', gap: '1rem', alignItems: 'flex-start' }}>
                        <label className="checkbox-label" style={{ marginBottom: 0 }}>
                          <input
                            type="checkbox"
                            checked={selectedItem.draggable !== false}
                            onChange={(e) => {
                              const isDraggable = e.target.checked;
                              const newColor = isDraggable ? '#007AFF' : '#999999';
                              setGeometryData(prev => ({
                                ...prev,
                                points: prev.points.map(p =>
                                  p.id === selectedItem.id ? { ...p, draggable: isDraggable, color: newColor } : p
                                )
                              }));
                              setSelectedItem(prev => ({ ...prev, draggable: isDraggable, color: newColor }));
                            }}
                          />
                          允许用户拖动
                        </label>

                        <label className="checkbox-label" style={{ marginBottom: 0 }}>
                          <input
                            type="checkbox"
                            checked={selectedItem.hidden === true}
                            onChange={(e) => {
                              const isHidden = e.target.checked;
                              setGeometryData(prev => ({
                                ...prev,
                                points: prev.points.map(p =>
                                  p.id === selectedItem.id ? { ...p, hidden: isHidden } : p
                                )
                              }));
                              setSelectedItem(prev => ({ ...prev, hidden: isHidden }));
                            }}
                          />
                          隐藏点{selectedItem.isFootPoint ? ' [垂足点]' : ''}
                        </label>
                      </div>

                      {/* 拖动约束 */}
                      {selectedItem.draggable !== false && (
                        <div className="form-group" style={{ marginTop: '0.75rem' }}>
                          <label style={{ marginBottom: '0.375rem', display: 'block', fontWeight: 600, fontSize: '0.8125rem' }}>
                            拖动约束
                          </label>
                          {(() => {
                            const pointConstraints = (geometryData.dragConstraints || []).filter(c => c.pointId === selectedItem.id);
                            return (
                              <>
                                {pointConstraints.map((constraint) => {
                                  const line = geometryData.lines.find(l => l.id === constraint.lineId);
                                  if (!line) return null;
                                  const startPoint = geometryData.points.find(p => p.id === line.startPointId);
                                  const endPoint = geometryData.points.find(p => p.id === line.endPointId);
                                  const lineLabel = `${startPoint?.label || '?'} → ${endPoint?.label || '?'}`;

                                  return (
                                    <div key={constraint.id} style={{
                                      display: 'flex',
                                      alignItems: 'center',
                                      justifyContent: 'space-between',
                                      padding: '0.375rem 0.5rem',
                                      background: '#fff3cd',
                                      borderRadius: '4px',
                                      marginBottom: '0.25rem',
                                      fontSize: '0.75rem'
                                    }}>
                                      <span>线段 {lineLabel}</span>
                                      <button
                                        onClick={() => {
                                          setGeometryData(prev => ({
                                            ...prev,
                                            dragConstraints: (prev.dragConstraints || []).filter(c => c.id !== constraint.id)
                                          }));
                                          toast.success('约束已删除');
                                        }}
                                        style={{
                                          background: 'none',
                                          border: 'none',
                                          color: '#dc3545',
                                          cursor: 'pointer',
                                          padding: '0.125rem'
                                        }}
                                      >
                                        <X size={14} />
                                      </button>
                                    </div>
                                  );
                                })}
                                <button
                                  onClick={() => {
                                    toast.info('点击一条线段来添加约束');
                                    setAddingConstraintMode('drag');
                                    // 进入选择线段模式
                                    const handleCanvasClick = (e) => {
                                      e.stopPropagation();
                                      const coords = getCanvasCoords(e);
                                      const clickedLine = findClickedLineLocal(coords.x, coords.y);
                                      if (clickedLine) {
                                        const { item: line } = clickedLine;
                                        // 检查是否已经有这个约束
                                        const exists = (geometryData.dragConstraints || []).some(
                                          c => c.pointId === selectedItem.id && c.lineId === line.id
                                        );
                                        if (!exists) {
                                          setGeometryData(prev => ({
                                            ...prev,
                                            dragConstraints: [
                                              ...(prev.dragConstraints || []),
                                              {
                                                id: `constraint_${Date.now()}`,
                                                pointId: selectedItem.id,
                                                lineId: line.id
                                              }
                                            ]
                                          }));
                                          toast.success('约束已添加');
                                        } else {
                                          toast.info('该约束已存在');
                                        }
                                      }
                                      setAddingConstraintMode(null);
                                      canvasRef.current?.removeEventListener('click', handleCanvasClick);
                                    };
                                    canvasRef.current?.addEventListener('click', handleCanvasClick, { once: true });
                                  }}
                                  style={{
                                    width: '100%',
                                    padding: '0.375rem',
                                    fontSize: '0.75rem',
                                    background: '#007bff',
                                    color: 'white',
                                    border: 'none',
                                    borderRadius: '4px',
                                    cursor: 'pointer',
                                    display: 'flex',
                                    alignItems: 'center',
                                    justifyContent: 'center',
                                    gap: '0.25rem'
                                  }}
                                >
                                  <Plus size={14} />
                                  添加约束线段
                                </button>
                              </>
                            );
                          })()}
                        </div>
                      )}

                      {/* 滑动点约束 - 仅对滑动点显示 */}
                      {selectedItem.constrainedToLine && (
                        <div className="form-group" style={{ marginTop: '0.75rem' }}>
                          <label style={{ marginBottom: '0.375rem', display: 'block', fontWeight: 600, fontSize: '0.8125rem' }}>
                            滑动点约束
                          </label>
                          <p style={{ fontSize: '0.75rem', color: '#666', marginBottom: '0.5rem' }}>
                            选择点来限制此滑动点的滑动范围
                          </p>
                          {(() => {
                            const slidingConstraints = (geometryData.slidingConstraints || []).filter(c => c.slidingPointId === selectedItem.id);
                            return (
                              <>
                                {slidingConstraints.map((constraint) => {
                                  const constraintPoint = geometryData.points.find(p => p.id === constraint.constraintPointId);
                                  if (!constraintPoint) return null;

                                  return (
                                    <div key={constraint.id} style={{
                                      display: 'flex',
                                      alignItems: 'center',
                                      justifyContent: 'space-between',
                                      padding: '0.375rem 0.5rem',
                                      background: '#d4edff',
                                      borderRadius: '4px',
                                      marginBottom: '0.25rem',
                                      fontSize: '0.75rem'
                                    }}>
                                      <span>约束点: {constraintPoint.label || `点${constraintPoint.id}`}</span>
                                      <button
                                        onClick={() => {
                                          setGeometryData(prev => ({
                                            ...prev,
                                            slidingConstraints: (prev.slidingConstraints || []).filter(c => c.id !== constraint.id)
                                          }));
                                          toast.success('滑动点约束已删除');
                                        }}
                                        style={{
                                          background: 'none',
                                          border: 'none',
                                          color: '#dc3545',
                                          cursor: 'pointer',
                                          padding: '0.125rem'
                                        }}
                                      >
                                        <X size={14} />
                                      </button>
                                    </div>
                                  );
                                })}
                                <button
                                  onClick={() => {
                                    toast.info('点击一个点来添加滑动点约束');
                                    setAddingConstraintMode('sliding');
                                    // 进入选择点模式
                                    const handleCanvasClick = (e) => {
                                      e.stopPropagation();
                                      const coords = getCanvasCoords(e);
                                      const clickedPoint = findClickedPointLocal(coords.x, coords.y);
                                      if (clickedPoint) {
                                        const { item: point } = clickedPoint;
                                        // 不能约束自己
                                        if (point.id === selectedItem.id) {
                                          toast.warning('不能约束自己');
                                          setAddingConstraintMode(null);
                                          canvasRef.current?.removeEventListener('click', handleCanvasClick);
                                          return;
                                        }
                                        // 检查是否已经有这个约束
                                        const exists = (geometryData.slidingConstraints || []).some(
                                          c => c.slidingPointId === selectedItem.id && c.constraintPointId === point.id
                                        );
                                        if (!exists) {
                                          setGeometryData(prev => ({
                                            ...prev,
                                            slidingConstraints: [
                                              ...(prev.slidingConstraints || []),
                                              {
                                                id: `sliding_constraint_${Date.now()}`,
                                                slidingPointId: selectedItem.id,
                                                constraintPointId: point.id
                                              }
                                            ]
                                          }));
                                          toast.success('滑动点约束已添加');
                                        } else {
                                          toast.info('该约束已存在');
                                        }
                                      }
                                      setAddingConstraintMode(null);
                                      canvasRef.current?.removeEventListener('click', handleCanvasClick);
                                    };
                                    canvasRef.current?.addEventListener('click', handleCanvasClick, { once: true });
                                  }}
                                  style={{
                                    width: '100%',
                                    padding: '0.375rem',
                                    fontSize: '0.75rem',
                                    background: '#17a2b8',
                                    color: 'white',
                                    border: 'none',
                                    borderRadius: '4px',
                                    cursor: 'pointer',
                                    display: 'flex',
                                    alignItems: 'center',
                                    justifyContent: 'center',
                                    gap: '0.25rem'
                                  }}
                                >
                                  <Plus size={14} />
                                  添加约束点
                                </button>
                              </>
                            );
                          })()}
                        </div>
                      )}

                      {/* 显示与该点关联的线段 */}
                      {(() => {
                        const relatedLines = geometryData.lines.filter(line =>
                          line.startPointId === selectedItem.id || line.endPointId === selectedItem.id
                        );

                        if (relatedLines.length > 0) {
                          return (
                            <div className="form-group" style={{ marginTop: '0.75rem' }}>
                              <label style={{ marginBottom: '0.375rem', display: 'block', fontWeight: 600, fontSize: '0.8125rem' }}>
                                关联线段 ({relatedLines.length})
                              </label>
                              {relatedLines.map((line) => {
                                const startPoint = geometryData.points.find(p => p.id === line.startPointId);
                                const endPoint = geometryData.points.find(p => p.id === line.endPointId);
                                const lineLabel = `${startPoint?.label || '?'} → ${endPoint?.label || '?'}`;
                                const isEditingThisLine = pointOnLineMode?.lineId === line.id;

                                return (
                                  <div key={line.id} style={{
                                    marginBottom: '0.5rem',
                                    padding: '0.5rem',
                                    background: '#f5f5f7',
                                    borderRadius: '6px',
                                    border: '1px solid #e5e5e7'
                                  }}>
                                    <div style={{
                                      marginBottom: '0.375rem',
                                      fontWeight: 500,
                                      fontSize: '0.8125rem',
                                      color: '#1d1d1f'
                                    }}>
                                      {lineLabel}
                                    </div>

                                    <div style={{ marginBottom: '0.375rem' }}>
                                      <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                        标签
                                      </label>
                                      <div style={{ display: 'flex', gap: '0.25rem' }}>
                                        <input
                                          type="text"
                                          value={line.label || ''}
                                          onChange={(e) => {
                                            const newLabel = e.target.value;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              lines: prev.lines.map(l =>
                                                l.id === line.id ? { ...l, label: newLabel } : l
                                              )
                                            }));
                                          }}
                                          placeholder="如: AB, l₁"
                                          style={{ flex: 1, padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                        />
                                        {line.labelOffset && (line.labelOffset.x !== 0 || line.labelOffset.y !== 0) && (
                                          <button
                                            onClick={() => {
                                              setGeometryData(prev => ({
                                                ...prev,
                                                lines: prev.lines.map(l =>
                                                  l.id === line.id ? { ...l, labelOffset: { x: 0, y: 0 } } : l
                                                )
                                              }));
                                              toast.success('标签位置已重置');
                                            }}
                                            title="重置标签位置"
                                            style={{
                                              padding: '0.25rem 0.5rem',
                                              fontSize: '0.75rem',
                                              background: '#6c757d',
                                              color: 'white',
                                              border: 'none',
                                              borderRadius: '4px',
                                              cursor: 'pointer'
                                            }}
                                          >
                                            重置
                                          </button>
                                        )}
                                      </div>
                                    </div>

                                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 60px', gap: '0.375rem', marginBottom: '0.375rem' }}>
                                      <div>
                                        <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                          样式
                                        </label>
                                        <select
                                          value={line.style || 'solid'}
                                          onChange={(e) => {
                                            const newStyle = e.target.value;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              lines: prev.lines.map(l =>
                                                l.id === line.id ? { ...l, style: newStyle } : l
                                              )
                                            }));
                                          }}
                                          style={{ width: '100%', padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                        >
                                          <option value="solid">实线</option>
                                          <option value="dashed">虚线</option>
                                          <option value="hidden">隐藏</option>
                                        </select>
                                      </div>

                                      <div>
                                        <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                          线宽
                                        </label>
                                        <input
                                          type="number"
                                          value={line.width || 2}
                                          onChange={(e) => {
                                            const newWidth = parseInt(e.target.value);
                                            setGeometryData(prev => ({
                                              ...prev,
                                              lines: prev.lines.map(l =>
                                                l.id === line.id ? { ...l, width: newWidth } : l
                                              )
                                            }));
                                          }}
                                          min="1"
                                          max="10"
                                          style={{ width: '100%', padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                        />
                                      </div>
                                    </div>

                                    <div style={{ marginBottom: '0.375rem' }}>
                                      <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                        颜色
                                      </label>
                                      <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>
                                        {LINE_COLORS.map((color, idx) => (
                                          <button
                                            key={idx}
                                            className={`fill-color-btn ${line.color === color.value ? 'active' : ''}`}
                                            style={{
                                              width: '20px',
                                              height: '20px',
                                              borderRadius: '3px',
                                              backgroundColor: color.value,
                                              border: line.color === color.value ? '2px solid #000' : '1px solid #ccc',
                                              cursor: 'pointer',
                                              padding: 0
                                            }}
                                            onClick={() => {
                                              setGeometryData(prev => ({
                                                ...prev,
                                                lines: prev.lines.map(l =>
                                                  l.id === line.id ? { ...l, color: color.value } : l
                                                )
                                              }));
                                            }}
                                            title={`${color.name}`}
                                          />
                                        ))}
                                        {/* 色盘选择器 */}
                                        <input
                                          type="color"
                                          id={`line-color-picker-${line.id}`}
                                          style={{ display: 'none' }}
                                          value={line.color || '#333'}
                                          onChange={(e) => {
                                            const newColor = e.target.value;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              lines: prev.lines.map(l =>
                                                l.id === line.id ? { ...l, color: newColor } : l
                                              )
                                            }));
                                          }}
                                        />
                                        <button
                                          className="fill-color-picker-btn"
                                          style={{
                                            width: '20px',
                                            height: '20px',
                                            borderRadius: '3px',
                                            backgroundColor: '#fff',
                                            border: '1px solid #ccc',
                                            cursor: 'pointer',
                                            padding: 0,
                                            fontSize: '12px',
                                            lineHeight: '18px',
                                            display: 'flex',
                                            alignItems: 'center',
                                            justifyContent: 'center'
                                          }}
                                          onClick={() => {
                                            document.getElementById(`line-color-picker-${line.id}`).click();
                                          }}
                                          title="选择自定义颜色"
                                        >
                                          🎨
                                        </button>
                                      </div>
                                    </div>

                                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: '0.25rem' }}>
                                      <button
                                        className={`tool-btn ${isEditingThisLine && pointOnLineMode.type === 'slide' ? 'active' : ''}`}
                                        onClick={() => {
                                          if (isEditingThisLine && pointOnLineMode.type === 'slide') {
                                            setPointOnLineMode(null);
                                            setCurrentTool('select');
                                            toast.info('已退出编辑');
                                          } else {
                                            setSelectedItem({ ...line, type: 'line' });
                                            setPointOnLineMode({ type: 'slide', lineId: line.id });
                                            setCurrentTool('pointOnLine');
                                            toast.info(`点击线段添加滑动点`);
                                          }
                                        }}
                                        style={{
                                          padding: '0.25rem',
                                          fontSize: '0.6875rem',
                                          display: 'flex',
                                          alignItems: 'center',
                                          justifyContent: 'center',
                                          gap: '0.25rem',
                                          flexDirection: 'column'
                                        }}
                                        title="添加可拖动的滑动点"
                                      >
                                        <Move size={12} />
                                        <span>滑动点</span>
                                      </button>
                                      <button
                                        className={`tool-btn ${isEditingThisLine && pointOnLineMode.type === 'fixed' ? 'active' : ''}`}
                                        onClick={() => {
                                          if (isEditingThisLine && pointOnLineMode.type === 'fixed') {
                                            setPointOnLineMode(null);
                                            setCurrentTool('select');
                                            toast.info('已退出编辑');
                                          } else {
                                            setSelectedItem({ ...line, type: 'line' });
                                            setPointOnLineMode({ type: 'fixed', lineId: line.id });
                                            setCurrentTool('pointOnLine');
                                            toast.info(`点击线段添加定点`);
                                          }
                                        }}
                                        style={{
                                          padding: '0.25rem',
                                          fontSize: '0.6875rem',
                                          display: 'flex',
                                          alignItems: 'center',
                                          justifyContent: 'center',
                                          gap: '0.25rem',
                                          flexDirection: 'column'
                                        }}
                                        title="添加定点（固定位置，不可拖动）"
                                      >
                                        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                          <circle cx="12" cy="12" r="10"></circle>
                                          <circle cx="12" cy="12" r="3"></circle>
                                        </svg>
                                        <span>定点</span>
                                      </button>
                                      <button
                                        className={`tool-btn ${isEditingThisLine && pointOnLineMode.type === 'divide' ? 'active' : ''}`}
                                        onClick={async () => {
                                          if (isEditingThisLine && pointOnLineMode.type === 'divide') {
                                            setPointOnLineMode(null);
                                            setCurrentTool('select');
                                            toast.info('已退出编辑');
                                          } else {
                                            const result = await showDialog({
                                              title: '等分线段',
                                              message: '请输入等分数量',
                                              fields: [
                                                {
                                                  name: 'count',
                                                  label: '等分数量',
                                                  type: 'text',
                                                  placeholder: '输入等分数量（2-10）',
                                                  defaultValue: '3',
                                                  required: true,
                                                  validate: (value) => {
                                                    const num = parseInt(value);
                                                    if (isNaN(num) || num < 2 || num > 10) {
                                                      return '请输入2-10之间的数字';
                                                    }
                                                    return null;
                                                  }
                                                }
                                              ],
                                              confirmText: '确认',
                                              cancelText: '取消'
                                            });

                                            const count = result?.count;
                                            if (count && !isNaN(count) && parseInt(count) >= 2 && parseInt(count) <= 10) {
                                              const n = parseInt(count);
                                              const lineStart = geometryData.points.find(p => p.id === line.startPointId);
                                              const lineEnd = geometryData.points.find(p => p.id === line.endPointId);

                                              if (lineStart && lineEnd) {
                                                const newPoints = [];
                                                for (let i = 1; i < n; i++) {
                                                  const t = i / n;
                                                  const newPoint = {
                                                    id: `point_${Date.now()}_${i}`,
                                                    x: lineStart.x + t * (lineEnd.x - lineStart.x),
                                                    y: lineStart.y + t * (lineEnd.y - lineStart.y),
                                                    label: '',
                                                    color: '#66B3FF',
                                                    draggable: false,
                                                    constrainedToLine: {
                                                      lineId: line.id,
                                                      startPointId: line.startPointId,
                                                      endPointId: line.endPointId,
                                                      ratio: t
                                                    }
                                                  };
                                                  newPoints.push(newPoint);
                                                }

                                                setGeometryData(prev => ({
                                                  ...prev,
                                                  points: [...prev.points, ...newPoints]
                                                }));

                                                toast.success(`已添加 ${n - 1} 个等分点`);
                                              }
                                            } else if (count) {
                                              toast.error('请输入2-10之间的数字');
                                            }
                                          }
                                        }}
                                        style={{
                                          padding: '0.25rem',
                                          fontSize: '0.6875rem',
                                          display: 'flex',
                                          alignItems: 'center',
                                          justifyContent: 'center',
                                          gap: '0.25rem',
                                          flexDirection: 'column'
                                        }}
                                        title="添加等分点（不可拖动）"
                                      >
                                        <GitCommit size={12} />
                                        <span>等分点</span>
                                      </button>
                                    </div>
                                  </div>
                                );
                              })}
                            </div>
                          );
                        }
                        return null;
                      })()}

                      {/* 显示与该点关联的平行线 */}
                      {(() => {
                        const relatedParallels = (geometryData.parallels || []).filter(para =>
                          para.fromPointId === selectedItem.id
                        );

                        if (relatedParallels.length > 0) {
                          return (
                            <div className="form-group" style={{ marginTop: '0.75rem' }}>
                              <label style={{ marginBottom: '0.375rem', display: 'block', fontWeight: 600, fontSize: '0.8125rem' }}>
                                关联平行线 ({relatedParallels.length})
                              </label>
                              {relatedParallels.map((para) => {
                                const fromPoint = geometryData.points.find(p => p.id === para.fromPointId);
                                const lineStartPoint = geometryData.points.find(p => p.id === para.toLineStartId);
                                const lineEndPoint = geometryData.points.find(p => p.id === para.toLineEndId);
                                const paraLabel = `${fromPoint?.label || '?'} ∥ ${lineStartPoint?.label || '?'}${lineEndPoint?.label || '?'}`;

                                return (
                                  <div key={para.id} style={{
                                    marginBottom: '0.5rem',
                                    padding: '0.5rem',
                                    background: '#f5f5f7',
                                    borderRadius: '6px',
                                    border: '1px solid #e5e5e7'
                                  }}>
                                    <div style={{
                                      marginBottom: '0.375rem',
                                      fontWeight: 500,
                                      fontSize: '0.8125rem',
                                      color: '#1d1d1f'
                                    }}>
                                      {paraLabel}
                                    </div>

                                    <div style={{ marginBottom: '0.375rem' }}>
                                      <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                        标签
                                      </label>
                                      <input
                                        type="text"
                                        value={para.label || ''}
                                        onChange={(e) => {
                                          const newLabel = e.target.value;
                                          setGeometryData(prev => ({
                                            ...prev,
                                            parallels: prev.parallels.map(p =>
                                              p.id === para.id ? { ...p, label: newLabel } : p
                                            )
                                          }));
                                        }}
                                        placeholder="如: l₁"
                                        style={{ width: '100%', padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                      />
                                    </div>

                                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 60px', gap: '0.375rem', marginBottom: '0.375rem' }}>
                                      <div>
                                        <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                          样式
                                        </label>
                                        <select
                                          value={para.style || 'solid'}
                                          onChange={(e) => {
                                            const newStyle = e.target.value;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              parallels: prev.parallels.map(p =>
                                                p.id === para.id ? { ...p, style: newStyle } : p
                                              )
                                            }));
                                          }}
                                          style={{ width: '100%', padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                        >
                                          <option value="solid">实线</option>
                                          <option value="dashed">虚线</option>
                                          <option value="hidden">隐藏</option>
                                        </select>
                                      </div>

                                      <div>
                                        <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                          线宽
                                        </label>
                                        <input
                                          type="number"
                                          value={para.width || 2}
                                          onChange={(e) => {
                                            const newWidth = parseInt(e.target.value);
                                            setGeometryData(prev => ({
                                              ...prev,
                                              parallels: prev.parallels.map(p =>
                                                p.id === para.id ? { ...p, width: newWidth } : p
                                              )
                                            }));
                                          }}
                                          min="1"
                                          max="10"
                                          style={{ width: '100%', padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                        />
                                      </div>
                                    </div>

                                    <div style={{ marginBottom: '0.375rem' }}>
                                      <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                        颜色
                                      </label>
                                      <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>
                                        {LINE_COLORS.map((color, idx) => (
                                          <button
                                            key={idx}
                                            className={`fill-color-btn ${para.color === color.value ? 'active' : ''}`}
                                            style={{
                                              width: '20px',
                                              height: '20px',
                                              borderRadius: '3px',
                                              backgroundColor: color.value,
                                              border: para.color === color.value ? '2px solid #000' : '1px solid #ccc',
                                              cursor: 'pointer',
                                              padding: 0
                                            }}
                                            onClick={() => {
                                              setGeometryData(prev => ({
                                                ...prev,
                                                parallels: prev.parallels.map(p =>
                                                  p.id === para.id ? { ...p, color: color.value } : p
                                                )
                                              }));
                                            }}
                                            title={`${color.name}`}
                                          />
                                        ))}
                                        {/* 色盘选择器 */}
                                        <input
                                          type="color"
                                          id={`parallel-color-picker-${para.id}`}
                                          style={{ display: 'none' }}
                                          value={para.color || '#007AFF'}
                                          onChange={(e) => {
                                            const newColor = e.target.value;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              parallels: prev.parallels.map(p =>
                                                p.id === para.id ? { ...p, color: newColor } : p
                                              )
                                            }));
                                          }}
                                        />
                                        <button
                                          className="fill-color-picker-btn"
                                          style={{
                                            width: '20px',
                                            height: '20px',
                                            borderRadius: '3px',
                                            backgroundColor: '#fff',
                                            border: '1px solid #ccc',
                                            cursor: 'pointer',
                                            padding: 0,
                                            fontSize: '12px',
                                            lineHeight: '18px',
                                            display: 'flex',
                                            alignItems: 'center',
                                            justifyContent: 'center'
                                          }}
                                          onClick={() => {
                                            document.getElementById(`parallel-color-picker-${para.id}`).click();
                                          }}
                                          title="选择自定义颜色"
                                        >
                                          🎨
                                        </button>
                                      </div>
                                    </div>

                                    <button
                                      onClick={() => {
                                        setGeometryData(prev => ({
                                          ...prev,
                                          parallels: (prev.parallels || []).filter(p => p.id !== para.id)
                                        }));
                                        toast.success('平行线已删除');
                                      }}
                                      style={{
                                        width: '100%',
                                        background: '#ff3b30',
                                        color: 'white',
                                        border: 'none',
                                        borderRadius: '4px',
                                        padding: '0.375rem',
                                        fontSize: '0.75rem',
                                        cursor: 'pointer',
                                        fontWeight: 500
                                      }}
                                    >
                                      删除平行线
                                    </button>
                                  </div>
                                );
                              })}
                            </div>
                          );
                        }
                        return null;
                      })()}

                      {/* 显示与该点关联的垂线 */}
                      {(() => {
                        const relatedPerpendiculars = (geometryData.perpendiculars || []).filter(perp =>
                          perp.fromPointId === selectedItem.id || perp.footPointId === selectedItem.id
                        );

                        if (relatedPerpendiculars.length > 0) {
                          return (
                            <div className="form-group" style={{ marginTop: '0.75rem' }}>
                              <label style={{ marginBottom: '0.375rem', display: 'block', fontWeight: 600, fontSize: '0.8125rem' }}>
                                关联垂线 ({relatedPerpendiculars.length})
                              </label>
                              {relatedPerpendiculars.map((perp) => {
                                const fromPoint = geometryData.points.find(p => p.id === perp.fromPointId);
                                const lineStartPoint = geometryData.points.find(p => p.id === perp.toLineStartId);
                                const lineEndPoint = geometryData.points.find(p => p.id === perp.toLineEndId);
                                const perpLabel = `${fromPoint?.label || '?'} ⊥ ${lineStartPoint?.label || '?'}${lineEndPoint?.label || '?'}`;

                                return (
                                  <div key={perp.id} style={{
                                    marginBottom: '0.5rem',
                                    padding: '0.5rem',
                                    background: '#f5f5f7',
                                    borderRadius: '6px',
                                    border: '1px solid #e5e5e7'
                                  }}>
                                    <div style={{
                                      marginBottom: '0.375rem',
                                      fontWeight: 500,
                                      fontSize: '0.8125rem',
                                      color: '#1d1d1f'
                                    }}>
                                      {perpLabel}
                                    </div>

                                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 60px', gap: '0.375rem', marginBottom: '0.375rem' }}>
                                      <div>
                                        <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                          样式
                                        </label>
                                        <select
                                          value={perp.style || 'dashed'}
                                          onChange={(e) => {
                                            const newStyle = e.target.value;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              perpendiculars: prev.perpendiculars.map(p =>
                                                p.id === perp.id ? { ...p, style: newStyle } : p
                                              )
                                            }));
                                          }}
                                          style={{ width: '100%', padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                        >
                                          <option value="solid">实线</option>
                                          <option value="dashed">虚线</option>
                                          <option value="hidden">隐藏</option>
                                        </select>
                                      </div>

                                      <div>
                                        <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                          线宽
                                        </label>
                                        <input
                                          type="number"
                                          value={perp.width || 2}
                                          onChange={(e) => {
                                            const newWidth = parseInt(e.target.value);
                                            setGeometryData(prev => ({
                                              ...prev,
                                              perpendiculars: prev.perpendiculars.map(p =>
                                                p.id === perp.id ? { ...p, width: newWidth } : p
                                              )
                                            }));
                                          }}
                                          min="1"
                                          max="10"
                                          style={{ width: '100%', padding: '0.25rem', fontSize: '0.75rem', borderRadius: '4px', border: '1px solid #d2d2d7' }}
                                        />
                                      </div>
                                    </div>

                                    <div style={{ marginBottom: '0.375rem' }}>
                                      <label style={{ fontSize: '0.6875rem', color: '#86868b', marginBottom: '0.125rem', display: 'block' }}>
                                        颜色
                                      </label>
                                      <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>
                                        {LINE_COLORS.map((color, idx) => (
                                          <button
                                            key={idx}
                                            className={`fill-color-btn ${perp.color === color.value ? 'active' : ''}`}
                                            style={{
                                              width: '20px',
                                              height: '20px',
                                              borderRadius: '3px',
                                              backgroundColor: color.value,
                                              border: perp.color === color.value ? '2px solid #000' : '1px solid #ccc',
                                              cursor: 'pointer',
                                              padding: 0
                                            }}
                                            onClick={() => {
                                              setGeometryData(prev => ({
                                                ...prev,
                                                perpendiculars: prev.perpendiculars.map(p =>
                                                  p.id === perp.id ? { ...p, color: color.value } : p
                                                )
                                              }));
                                            }}
                                            title={`${color.name}`}
                                          />
                                        ))}
                                        {/* 色盘选择器 */}
                                        <input
                                          type="color"
                                          id={`perpendicular-color-picker-${perp.id}`}
                                          style={{ display: 'none' }}
                                          value={perp.color || '#666'}
                                          onChange={(e) => {
                                            const newColor = e.target.value;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              perpendiculars: prev.perpendiculars.map(p =>
                                                p.id === perp.id ? { ...p, color: newColor } : p
                                              )
                                            }));
                                          }}
                                        />
                                        <button
                                          className="fill-color-picker-btn"
                                          style={{
                                            width: '20px',
                                            height: '20px',
                                            borderRadius: '3px',
                                            backgroundColor: '#fff',
                                            border: '1px solid #ccc',
                                            cursor: 'pointer',
                                            padding: 0,
                                            fontSize: '12px',
                                            lineHeight: '18px',
                                            display: 'flex',
                                            alignItems: 'center',
                                            justifyContent: 'center'
                                          }}
                                          onClick={() => {
                                            document.getElementById(`perpendicular-color-picker-${perp.id}`).click();
                                          }}
                                          title="选择自定义颜色"
                                        >
                                          🎨
                                        </button>
                                      </div>
                                    </div>

                                    <div style={{ marginBottom: '0.375rem' }}>
                                      <label style={{
                                        fontSize: '0.6875rem',
                                        color: '#86868b',
                                        marginBottom: '0.25rem',
                                        display: 'flex',
                                        alignItems: 'center',
                                        gap: '0.25rem'
                                      }}>
                                        <input
                                          type="checkbox"
                                          checked={perp.showFoot !== false}
                                          onChange={(e) => {
                                            const showFoot = e.target.checked;
                                            setGeometryData(prev => ({
                                              ...prev,
                                              perpendiculars: prev.perpendiculars.map(p =>
                                                p.id === perp.id ? { ...p, showFoot } : p
                                              )
                                            }));
                                          }}
                                          style={{ width: 'auto', margin: 0 }}
                                        />
                                        显示垂足标记
                                      </label>
                                    </div>

                                    {/* 为垂线添加点操作按钮 */}
                                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: '0.25rem' }}>
                                      <button
                                        className={`tool-btn ${selectedItem && pointOnLineMode?.perpId === perp.id && pointOnLineMode.type === 'slide' ? 'active' : ''}`}
                                        onClick={() => {
                                          if (pointOnLineMode?.perpId === perp.id && pointOnLineMode.type === 'slide') {
                                            setPointOnLineMode(null);
                                            setCurrentTool('select');
                                            toast.info('已退出编辑');
                                          } else {
                                            // 创建虚拟线段对象用于点操作
                                            const virtLine = {
                                              id: perp.id,
                                              startPointId: perp.fromPointId,
                                              endPointId: perp.footPointId,
                                              isPerpendicular: true
                                            };
                                            setSelectedItem({ ...virtLine, type: 'line' });
                                            setPointOnLineMode({ type: 'slide', lineId: perp.id, perpId: perp.id });
                                            setCurrentTool('pointOnLine');
                                            toast.info(`点击垂线添加滑动点`);
                                          }
                                        }}
                                        style={{
                                          padding: '0.25rem',
                                          fontSize: '0.6875rem',
                                          display: 'flex',
                                          alignItems: 'center',
                                          justifyContent: 'center',
                                          gap: '0.25rem',
                                          flexDirection: 'column'
                                        }}
                                        title="添加可拖动的滑动点"
                                      >
                                        <Move size={12} />
                                        <span>滑动点</span>
                                      </button>
                                      <button
                                        className={`tool-btn ${selectedItem && pointOnLineMode?.perpId === perp.id && pointOnLineMode.type === 'fixed' ? 'active' : ''}`}
                                        onClick={() => {
                                          if (pointOnLineMode?.perpId === perp.id && pointOnLineMode.type === 'fixed') {
                                            setPointOnLineMode(null);
                                            setCurrentTool('select');
                                            toast.info('已退出编辑');
                                          } else {
                                            const virtLine = {
                                              id: perp.id,
                                              startPointId: perp.fromPointId,
                                              endPointId: perp.footPointId,
                                              isPerpendicular: true
                                            };
                                            setSelectedItem({ ...virtLine, type: 'line' });
                                            setPointOnLineMode({ type: 'fixed', lineId: perp.id, perpId: perp.id });
                                            setCurrentTool('pointOnLine');
                                            toast.info(`点击垂线添加定点`);
                                          }
                                        }}
                                        style={{
                                          padding: '0.25rem',
                                          fontSize: '0.6875rem',
                                          display: 'flex',
                                          alignItems: 'center',
                                          justifyContent: 'center',
                                          gap: '0.25rem',
                                          flexDirection: 'column'
                                        }}
                                        title="添加定点（固定位置，不可拖动）"
                                      >
                                        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                          <circle cx="12" cy="12" r="10"></circle>
                                          <circle cx="12" cy="12" r="3"></circle>
                                        </svg>
                                        <span>定点</span>
                                      </button>
                                      <button
                                        className={`tool-btn ${selectedItem && pointOnLineMode?.perpId === perp.id && pointOnLineMode.type === 'divide' ? 'active' : ''}`}
                                        onClick={async () => {
                                          if (pointOnLineMode?.perpId === perp.id && pointOnLineMode.type === 'divide') {
                                            setPointOnLineMode(null);
                                            setCurrentTool('select');
                                            toast.info('已退出编辑');
                                          } else {
                                            const result = await showDialog({
                                              title: '等分垂线',
                                              message: '请输入等分数量',
                                              fields: [
                                                {
                                                  name: 'count',
                                                  label: '等分数量',
                                                  type: 'text',
                                                  placeholder: '输入等分数量（2-10）',
                                                  defaultValue: '3',
                                                  required: true,
                                                  validate: (value) => {
                                                    const num = parseInt(value);
                                                    if (isNaN(num) || num < 2 || num > 10) {
                                                      return '请输入2-10之间的数字';
                                                    }
                                                    return null;
                                                  }
                                                }
                                              ],
                                              confirmText: '确认',
                                              cancelText: '取消'
                                            });

                                            const count = result?.count;
                                            if (count && !isNaN(count) && parseInt(count) >= 2 && parseInt(count) <= 10) {
                                              const n = parseInt(count);
                                              const lineStart = geometryData.points.find(p => p.id === perp.fromPointId);
                                              const lineEnd = geometryData.points.find(p => p.id === perp.footPointId);

                                              if (lineStart && lineEnd) {
                                                const newPoints = [];
                                                for (let i = 1; i < n; i++) {
                                                  const t = i / n;
                                                  const newPoint = {
                                                    id: `point_${Date.now()}_${i}`,
                                                    x: lineStart.x + t * (lineEnd.x - lineStart.x),
                                                    y: lineStart.y + t * (lineEnd.y - lineStart.y),
                                                    label: '',
                                                    color: '#66B3FF',
                                                    draggable: false,
                                                    constrainedToLine: {
                                                      lineId: perp.id,
                                                      startPointId: perp.fromPointId,
                                                      endPointId: perp.footPointId,
                                                      ratio: t,
                                                      isPerpendicular: true
                                                    }
                                                  };
                                                  newPoints.push(newPoint);
                                                }

                                                setGeometryData(prev => ({
                                                  ...prev,
                                                  points: [...prev.points, ...newPoints]
                                                }));

                                                toast.success(`已添加 ${n - 1} 个等分点`);
                                              }
                                            } else if (count) {
                                              toast.error('请输入2-10之间的数字');
                                            }
                                          }
                                        }}
                                        style={{
                                          padding: '0.25rem',
                                          fontSize: '0.6875rem',
                                          display: 'flex',
                                          alignItems: 'center',
                                          justifyContent: 'center',
                                          gap: '0.25rem',
                                          flexDirection: 'column'
                                        }}
                                        title="添加等分点（不可拖动）"
                                      >
                                        <GitCommit size={12} />
                                        <span>等分点</span>
                                      </button>
                                    </div>
                                  </div>
                                );
                              })}
                            </div>
                          );
                        }
                        return null;
                      })()}
                    </div>
                  )}
                  {selectedItem.type === 'line' && (
                    <div className="selected-info" style={{ margin: '0 0.875rem' }}>
                      <p><strong>类型:</strong> 线段</p>
                      {(() => {
                        const line = geometryData.lines.find(l => l.id === selectedItem.id);
                        if (!line) return null;

                        const startPoint = geometryData.points.find(p => p.id === line.startPointId);
                        const endPoint = geometryData.points.find(p => p.id === line.endPointId);

                        return (
                          <>
                            <p><strong>起点:</strong> {startPoint?.label || line.startPointId.slice(-4)}</p>
                            <p><strong>终点:</strong> {endPoint?.label || line.endPointId.slice(-4)}</p>

                            <div className="form-group">
                              <label>样式</label>
                              <select
                                value={line.style || 'solid'}
                                onChange={(e) => {
                                  const newStyle = e.target.value;
                                  setGeometryData(prev => ({
                                    ...prev,
                                    lines: prev.lines.map(l =>
                                      l.id === line.id ? { ...l, style: newStyle } : l
                                    )
                                  }));
                                }}
                              >
                                <option value="solid">实线</option>
                                <option value="dashed">虚线</option>
                                <option value="hidden">隐藏</option>
                              </select>
                            </div>

                            <div className="form-group">
                              <label>线宽</label>
                              <input
                                type="number"
                                value={line.width || 2}
                                onChange={(e) => {
                                  const newWidth = parseInt(e.target.value);
                                  setGeometryData(prev => ({
                                    ...prev,
                                    lines: prev.lines.map(l =>
                                      l.id === line.id ? { ...l, width: newWidth } : l
                                    )
                                  }));
                                }}
                                min="1"
                                max="10"
                              />
                            </div>

                            <div className="form-group">
                              <label>颜色</label>
                              <div style={{ display: 'flex', gap: '4px', alignItems: 'center', flexWrap: 'wrap' }}>
                                {LINE_COLORS.map((color, idx) => (
                                  <button
                                    key={idx}
                                    className={`fill-color-btn ${line.color === color.value ? 'active' : ''}`}
                                    style={{
                                      width: '24px',
                                      height: '24px',
                                      borderRadius: '4px',
                                      backgroundColor: color.value,
                                      border: line.color === color.value ? '2px solid #000' : '1px solid #ccc',
                                      cursor: 'pointer',
                                      padding: 0
                                    }}
                                    onClick={() => {
                                      setGeometryData(prev => ({
                                        ...prev,
                                        lines: prev.lines.map(l =>
                                          l.id === line.id ? { ...l, color: color.value } : l
                                        )
                                      }));
                                    }}
                                    title={`${color.name}`}
                                  />
                                ))}
                                <input
                                  type="color"
                                  id="line-color-picker"
                                  style={{ display: 'none' }}
                                  value={line.color || '#333'}
                                  onChange={(e) => {
                                    const newColor = e.target.value;
                                    setGeometryData(prev => ({
                                      ...prev,
                                      lines: prev.lines.map(l =>
                                        l.id === line.id ? { ...l, color: newColor } : l
                                      )
                                    }));
                                  }}
                                />
                                <button
                                  className="fill-color-picker-btn"
                                  style={{
                                    width: '24px',
                                    height: '24px',
                                    borderRadius: '4px',
                                    backgroundColor: '#fff',
                                    border: '1px solid #ccc',
                                    cursor: 'pointer',
                                    padding: 0,
                                    fontSize: '14px',
                                    display: 'flex',
                                    alignItems: 'center',
                                    justifyContent: 'center'
                                  }}
                                  onClick={() => document.getElementById('line-color-picker').click()}
                                  title="自定义颜色"
                                >
                                  +
                                </button>
                              </div>
                            </div>

                            <button
                              className="delete-btn"
                              onClick={() => {
                                setGeometryData(prev => ({
                                  ...prev,
                                  lines: prev.lines.filter(l => l.id !== line.id)
                                }));
                                setSelectedItem(null);
                                toast.success('线段已删除');
                              }}
                              style={{ marginTop: '0.5rem' }}
                            >
                              <Trash2 size={14} />
                              删除线段
                            </button>
                          </>
                        );
                      })()}
                    </div>
                  )}

                  {selectedItem.type === 'ray' && (
                    <div className="selected-info" style={{ margin: '0 0.875rem' }}>
                      <p><strong>类型:</strong> 射线</p>
                      {(() => {
                        const ray = geometryData.rays.find(r => r.id === selectedItem.id);
                        if (!ray) return null;

                        const startPoint = geometryData.points.find(p => p.id === ray.startPointId);
                        const throughPoint = geometryData.points.find(p => p.id === ray.throughPointId);

                        return (
                          <>
                            <p><strong>起点:</strong> {startPoint?.label || ray.startPointId.slice(-4)}</p>
                            <p><strong>经过点:</strong> {throughPoint?.label || ray.throughPointId.slice(-4)}</p>

                            <div className="form-group">
                              <label>样式</label>
                              <select
                                value={ray.style || 'solid'}
                                onChange={(e) => {
                                  const newStyle = e.target.value;
                                  setGeometryData(prev => ({
                                    ...prev,
                                    rays: prev.rays.map(r =>
                                      r.id === ray.id ? { ...r, style: newStyle } : r
                                    )
                                  }));
                                }}
                              >
                                <option value="solid">实线</option>
                                <option value="dashed">虚线</option>
                                <option value="hidden">隐藏</option>
                              </select>
                            </div>

                            <div className="form-group">
                              <label>线宽</label>
                              <input
                                type="number"
                                value={ray.width || 2}
                                onChange={(e) => {
                                  const newWidth = parseInt(e.target.value);
                                  setGeometryData(prev => ({
                                    ...prev,
                                    rays: prev.rays.map(r =>
                                      r.id === ray.id ? { ...r, width: newWidth } : r
                                    )
                                  }));
                                }}
                                min="1"
                                max="10"
                              />
                            </div>

                            <div className="form-group">
                              <label>颜色</label>
                              <div style={{ display: 'flex', gap: '4px', alignItems: 'center', flexWrap: 'wrap' }}>
                                {LINE_COLORS.map((color, idx) => (
                                  <button
                                    key={idx}
                                    className={`fill-color-btn ${ray.color === color.value ? 'active' : ''}`}
                                    style={{
                                      width: '24px',
                                      height: '24px',
                                      borderRadius: '4px',
                                      backgroundColor: color.value,
                                      border: ray.color === color.value ? '2px solid #000' : '1px solid #ccc',
                                      cursor: 'pointer',
                                      padding: 0
                                    }}
                                    onClick={() => {
                                      setGeometryData(prev => ({
                                        ...prev,
                                        rays: prev.rays.map(r =>
                                          r.id === ray.id ? { ...r, color: color.value } : r
                                        )
                                      }));
                                    }}
                                    title={`${color.name}`}
                                  />
                                ))}
                                <input
                                  type="color"
                                  id="ray-color-picker"
                                  style={{ display: 'none' }}
                                  value={ray.color || '#333'}
                                  onChange={(e) => {
                                    const newColor = e.target.value;
                                    setGeometryData(prev => ({
                                      ...prev,
                                      rays: prev.rays.map(r =>
                                        r.id === ray.id ? { ...r, color: newColor } : r
                                      )
                                    }));
                                  }}
                                />
                                <button
                                  className="fill-color-picker-btn"
                                  style={{
                                    width: '24px',
                                    height: '24px',
                                    borderRadius: '4px',
                                    backgroundColor: '#fff',
                                    border: '1px solid #ccc',
                                    cursor: 'pointer',
                                    padding: 0,
                                    fontSize: '14px',
                                    display: 'flex',
                                    alignItems: 'center',
                                    justifyContent: 'center'
                                  }}
                                  onClick={() => document.getElementById('ray-color-picker').click()}
                                  title="自定义颜色"
                                >
                                  +
                                </button>
                              </div>
                            </div>

                            <button
                              className="delete-btn"
                              onClick={() => {
                                setGeometryData(prev => ({
                                  ...prev,
                                  rays: prev.rays.filter(r => r.id !== ray.id)
                                }));
                                setSelectedItem(null);
                                toast.success('射线已删除');
                              }}
                              style={{ marginTop: '0.5rem' }}
                            >
                              <Trash2 size={14} />
                              删除射线
                            </button>
                          </>
                        );
                      })()}
                    </div>
                  )}

                  {selectedItem.type === 'label' && (
                    <div className="selected-info" style={{ margin: '0 0.875rem' }}>
                      <p><strong>类型:</strong> {selectedItem.isAreaLabel ? '面积标签' : '标签'}</p>
                      <div className="form-group">
                        <label>文本</label>
                        <input
                          type="text"
                          value={selectedItem.text || ''}
                          onChange={(e) => {
                            const newText = e.target.value;
                            setGeometryData(prev => ({
                              ...prev,
                              labels: prev.labels.map(l =>
                                l.id === selectedItem.id ? { ...l, text: newText } : l
                              )
                            }));
                            setSelectedItem(prev => ({ ...prev, text: newText }));
                          }}
                        />
                      </div>
                      {/* 面积标签不显示方向选择（始终居中） */}
                      {!selectedItem.isAreaLabel && (
                        <div className="form-group">
                          <label>方向</label>
                          <select
                            value={selectedItem.direction || 'right'}
                            onChange={(e) => {
                              const newDirection = e.target.value;
                              setGeometryData(prev => ({
                                ...prev,
                                labels: prev.labels.map(l =>
                                  l.id === selectedItem.id ? { ...l, direction: newDirection } : l
                                )
                              }));
                              setSelectedItem(prev => ({ ...prev, direction: newDirection }));
                            }}
                          >
                            <option value="right">右</option>
                            <option value="left">左</option>
                            <option value="top">上</option>
                            <option value="bottom">下</option>
                          </select>
                        </div>
                      )}
                      <div className="form-group">
                        <label>字体大小</label>
                        <input
                          type="number"
                          value={selectedItem.fontSize || 16}
                          onChange={(e) => {
                            const newSize = parseInt(e.target.value);
                            setGeometryData(prev => ({
                              ...prev,
                              labels: prev.labels.map(l =>
                                l.id === selectedItem.id ? { ...l, fontSize: newSize } : l
                              )
                            }));
                            setSelectedItem(prev => ({ ...prev, fontSize: newSize }));
                          }}
                          min="10"
                          max="48"
                        />
                      </div>
                    </div>
                  )}
                </>
              )}
            </div>
          )}
        </div>
      </div>

      {/* Toast 容器 */}
      <ToastContainer toasts={toast.toasts} removeToast={toast.removeToast} />

      {/* Confirm 对话框 */}
      {confirmState && <Confirm {...confirmState} />}

      {/* Dialog 对话框 */}
      {dialogState && <Dialog {...dialogState} />}

      {/* Select 对话框 */}
      {selectState && <Select {...selectState} />}
    </>
  );
}



export default GeometryWorkspace;

